Git collaboration on Nostr: mirror code from any forge, run issues and pull requests with signed events, publish Pages, discover apps, and use Lightning bounties. Import from GitHub, GitLab, or Codeberg when you want a backup — not because gittr is a copy of another site.
NIPs & event kinds: Nostr schemata on gittr (nostrability) — e.g. NIP-34 for git repos, issues, and PRs.
.apk (Zapstore). Other binaries on that same tag can be linked as extra NIP-82 assets; files stay on the forge. Zapstore listing is optional and free — see Publish Pages, Apps & Releases.For better security, download a NIP-07 browser extension like:
On mobile browsers: Mobile browsers don't support browser extensions. Install Nowser to sign via NIP-46/NIP-07, or use a remote signer (NIP-46) with a hardware device.
Once installed, the extension will automatically detect when you visit the login page and allow you to sign in securely.
You can create a new repository or import from GitHub/GitLab/Codeberg. There are three ways to get started:
Import an existing repository from GitHub, GitLab, or Codeberg:
owner/repo (e.g. arbadacarbaYK/gittr)https://github.com/owner/repoLoad a GitHub user/org list, then choose what to import. Opening the bulk page does not import anything until you fetch, select, and confirm. GitHub only — GitLab / Codeberg / Gitea need Option 1 with a full URL (one repo at a time).
Web UI: Open the repo → Upload (or land there after Create empty). Drag & drop files or whole folders; nested paths like src/app/page.tsx are kept. Then Push to Nostr when ready.
Upload first syncs your browser to the published tip (when you have no unpushed edits), then merges your new files on top — so an older local cache cannot overwrite a newer Nostr/bridge state. If you already have unpushed local edits, upload merges into those instead (use Refresh from gittr only if you want to discard them).
If the Code tab already shows files from the network but Upload / Push complains about nothing local, use Refresh from gittr once (sidebar) so your browser stores a copy. Upload then merges your new files on top; Push publishes the combined tree.
Git CLI: after creating an empty repo, you can also push via Git:
git clone [email protected]:<pubkey>/<repo>.gitgit add . && git commit -m "Initial commit"git push origin mainImported repos already include files in the UI. The bridge only shows committed/pushed trees for empty creates.
Go to Settings → Account to configure LNbits (send/receive keys), Lightning address (lud16 / lnurl receive), or NWC. Repository-specific overrides live under each repo's Settings → Payment configuration.
gittr is installable as a Progressive Web App (PWA) on modern browsers. This gives you an app icon, standalone window, and offline fallback page.
Note: In-app browsers (Telegram/Twitter, etc.) often block PWA install. Open in the system browser. Offline mode only shows a fallback screen and does not replace full online functionality.
You can create repositories in three ways:
createRepo (HTTPS + nsec, no SSH). Operators can use gn repo create. Same git host as the website.All repos are stored locally in your browser and can be pushed to Nostr for public access. Tip: After Create empty, use Upload (files or folders, drag & drop) or push via Git — then Push to Nostr for public access.
📖 Complete Workflow for Empty Repositories
After creating an empty repository (website, MCP createRepo, or gn):
gn ssh-key add). The website is not in the SSH path after that.git clone [email protected]:<your-npub>/<repo-name>.git or HTTPS https://git.gittr.space/<hex>/<repo>.gitgit add . && git commit -m "Initial commit"git push origin mainFiles will appear in the web UI after pushing. See Git Operations section for detailed instructions.
a tag set each time).View, edit, and delete files or folders directly in the browser (owners: trash icon on each Code tree row, or Delete while a file is open). Deleting a folder marks it and everything inside for removal — the next Push to Nostr deletes it on the git host (GRASP / bridge), not just in this browser. Use the fuzzy file finder (Cmd/Ctrl+P) to quickly navigate large repositories.
Files live on git hosts (GRASP / gitnostr bridge), not inside Nostr events. NIP-34 announcements carry metadata and clone[] URLs. The Code sidebar shows where the tree is loading from: bridge / GRASP, GitHub, GitLab, and so on. Legacy “embedded in the event” trees are rare.
Bring an existing remote into gittr, then Push to Nostr so others can discover and clone it from GRASP / the bridge (not only from the original host). Details: When your git host goes dark.
git clone. Bulk import is GitHub-only. Forgejo/Gitea (including Codeberg and self-hosted) uses the same paste-URL import; Issues, PRs, and Releases then refresh from /api/v1. Nostr Pages and app announce work the same as for GitHub once a Release exists on that forge.npub…/repo, a gittr.space repo page, or a git.gittr.space clone URL on Option 1. The Fork button on a repo page uses the same import (parent files, not an empty About stub).gittr does not treat every git website the same under the hood. After you import, it refreshes metadata (fork parent, stars, issues, pull requests, releases) using one of three API families:
GitHub API → github.com
Bulk import, OAuth linking, and GitHub-specific metadata. Uses GitHub's REST API (/repos/…).
GitLab API → gitlab.com (and similar)
Paste a GitLab clone URL on Create repository. gittr uses GitLab's v4 API for fork parent lookup and tab refresh. Self-hosted GitLab instances with the same API shape work the same way.
Gitea / Forgejo API (/api/v1) → Codeberg, gitea.com, self-hosted Forgejo / Gitea
Forgejo is open-source forge software (a community fork of Gitea). Codeberg ( codeberg.org) is a popular public site that runs Forgejo — not a separate product. They share the same URL layout (host/owner/repo) and the same REST API, so gittr handles Codeberg, gitea.com, and your own Forgejo/Gitea server with one code path. Import is always paste-URL + git clone; Issues, PRs, Releases, and fork badges then refresh from /api/v1.
In short: GitHub, GitLab, and Gitea/Forgejo are three different "languages" gittr speaks. You still paste one clone URL — gittr picks the right API from the hostname.
GitHub import (/api/import) returns file paths and metadata, not file bodies. If that JSON is still larger than ~4 MB (very large trees), you get Repository is too large / repo_too_large. Import a smaller repo, or use a URL clone + Push to Nostr so the bridge holds the objects.
Paste-URL imports (/api/import-git) do not use that same 4 MB metadata cap. Huge binaries still belong in git LFS / releases on a real git host, not in the browser editor.
Privacy on gittr is tied to your Nostr pubkey, not your GitHub username. Settings → Private publishes ["public-read","false"] on kind 30617 (gittr extension; not core NIP-34). After Push, listings and the bridge honor that.
maintainers can open private repos (web, SSH, HTTPS).permission denied for read operation— ask the owner to add your npub.gittr.space repositories support multiple clone URL formats:
Option A: SSH (Standard Git - Recommended)
git clone [email protected]:npub1.../repo-name.gitFor laptop Git, like GitHub. Publish your public key once (Settings → SSH Keys, or gn ssh-key add). After that, clone/push never go through the website.
Option B: HTTPS (GRASP git servers)
git clone https://git.gittr.space/<owner-pubkey>/repo-name.gitSame bare repo as SSH. Public clones work over HTTPS. gittr-mcp pushes over HTTPS + a local nsec (no SSH, no Amber). Authenticated HTTPS is not read-only.
Option C: nostr:// Protocol (Ecosystem Standard)
git clone nostr://[email protected]/repo-nameRequires git-remote-nostr. This helper translates nostr:// URLs into standard Git fetches and is used by other NIP-34 clients.
Install git-remote-nostr
pip install git-remote-nostr (Python 3.10+)which git-remote-nostr)How it works:
Once installed, git clone nostr://… works with or without SSH keys - git-remote-nostr automatically chooses the best option.
SSH, HTTPS, and nostr:// clone URLs all ship inside every NIP-34 repository event. Pick whichever matches your workflow.
NIP-34 events carry metadata (name, description,clone[] URLs) — not the full file tree. gittr loads the tree from git servers and our bridge mirror.
source or GitHub clone URL existsclone[] (in parallel): read our on-disk mirror, or shallow-clone that URL directly, or mirror it onto gittr then readIf one mirror is down (502) but another works (e.g. relay.ngit.dev), you still get files from the working URL. The status chip on the repo shows ✓/✗ per source.
SSH / CLI vs Code tab: git clone [email protected]:… reads the same bridge bare repo the Code tab uses. The website additionally walks published clone[] /source URLs (forge first, then GRASP mirrors). File timestamps on the Code list come from the selected tip/branch on that mirror. Clone URL chips should list every pushable GRASP host from the event (not only git.gittr.space). After a clean Push with a forge source, the tip should match the forge — not a new empty “Push from gittr” commit. Details: FILE_FETCHING_INSIGHTS.md.
Newest metadata: we use the latest kind 30617 from relays. Newest commit across all mirrors: we currently show the first mirror that responds with a tree, not a full compare of every server's HEAD — see FILE_FETCHING_INSIGHTS.md.
Day-to-day
git pull / git fetchgit checkout <branch>git statusgit add / git commitPublishing
Use Push to Nostr on the Code tab. Approve with whatever you logged in with: NIP-07 extension, NIP-46 remote signer (Amber / bunker), or nsec. That publishes the NIP‑34 announcement to your relays and, on gittr, tries to mirror the Git repo to git.gittr.space so clones here work. Imported repos still keep their original forge (GitHub, etc.) as the source — the bridge is a mirror, not the only copy.
CLI fan? You can still run git push origin main to a bridge remote; that updates the same gittr mirror.
Branches & Tags
git branch -a / git switch -cgit tag v1.2.3Git tags are part of the repo history after you push them. Downloadable release files live on the forge Releases page — see Releases & where they live.
Troubleshooting
git remote -vgit config --listgit log --onelineAfter making local changes, click Push to Nostr on the Code tab (sidebar). Result and cache-flush messages open in a gittr dialog that grows to fit the full text (not the browser's tiny alert box). Sign with NIP-07, Amber / NIP-46 remote signer, or nsec — same login as Settings. Or use gittr-mcp publishRepoAnnouncement / createRepo (same events, local nsec, no SSH).
Amber must stay open/unlocked on your phone. Push first opens sockets to Amber's bunker relays; if that fails, nothing is published. Hard-refresh once if a previous page load left those relays stuck, then try Push again.
That does two different things — and it does not create a forge Release, upload installers, or list the app on /apps. Those are separate, on-purpose steps (Releases, Pages & Apps):
git.gittr.space so people can clone from here. That usually works after Push, but it is not guaranteed if the mirror step fails.Imported repos: Push does not move your project off GitHub/GitLab/Codeberg. The forge stays the original (source). gittr lists its bridge/GRASP URLs for Nostr clients and tries to mirror objects onto the bridge. Other GRASP hosts (e.g. relay.ngit.dev) may also appear in clone links if configured — those are extra mirrors/links, not “everything lives only on gittr.”
If you see "Please repush on local edits", use Push to Nostr so relays (and the mirror attempt) get those edits. Import alone stays local until you Push. For repos that already live on the gittr bridge but not in this browser, Refresh from gittr (or just Upload — it will prepare a local copy) before Push.
📦 Where files come from during Push
If you already edited files in the browser, those local files are uploaded to the bridge. For a clean import with no local edits, the bridge often clones from the forge source URL instead.
If the tree looks empty after Push: Re-import or open the repo so files load, then Push again — or git push to a bridge remote.
⚡ Push Paywall (if enabled by repo owner)
pending invoice (BOLT11) directly. Pay it, then run git push again.Push payment required — pay the invoice, then retry.push payment authorization expired — create/pay a fresh invoice in the web UI, then git push again.Rough week for some self-hosted Git setups — here's the practical bit, no panic.
A normal git clone or gittr import only copies repo objects (commits, trees, blobs). It does not bring over Gitea's app.ini, internal token, or planted service hooks. Those stay on the compromised or shut-down host. So code you already imported into gittr is not carrying that server compromise with it.
What keeps the repo visible and cloneable online is an independent mirror: import (or clone) into gittr, then Push to Nostr. That publishes the announcement on relays and puts objects on GRASP / the bridge (git.gittr.space and other clone[] hosts). Others can keep discovering and cloning without the original forge.
Quick check: can someone still git clone from a URL in your announcement clone[] without the original host? If yes, that snapshot is fine. If every clone URL still points only at the dead host, finish a Push (or push to a GRASP remote) so the tree has somewhere else to live.
| Path | What is stored | If that host dies or gets taken down |
|---|---|---|
| gittr import, never Push to Nostr | Mostly browser localStorage plus a pointer (source) at the original forge. Objects are not the Gitea server compromise. | Not enough for others yet. Only your browser has the files; Push so relays and GRASP can serve them. |
| gittr import + successful Push to Nostr | Kind 30617 / 30618 on relays, and objects mirrored onto the GRASP / bridge hosts listed in clone[] (for example git.gittr.space) | Safe for that snapshot and still discoverable. Others clone from GRASP, not the original forge. If the old host was compromised, rotate secrets that lived only there (and any tokens you once committed inside the repo). |
| Forge Release assets (APK, AppImage, MSI, …) | Binary files on GitHub / Codeberg / GitLab (or another host). gittr's Releases tab mostly lists those links; it does not store the installers. | Download buttons that point at the dead forge break. Code you already Push'd to GRASP can still be cloned — that is source, not the release installers. See Releases & where they live. |
| Nostr Apps announce (NIP-82 / Zapstore) | Signed events on relays (app / release / asset). Asset url usually still points at the forge download. Listing appears on /apps and your profile Apps section. | The announce stays discoverable; the download may 404 if the forge is gone. Hashes on the event do not replace a live file unless you also host the blob elsewhere (Blossom / CDN). Pages (kind 35128) are different — those files are uploaded to Blossom. |
nak / git-remote-nostr announce with clone / source = original forge only | Metadata on Nostr pointing at the original forge | Not enough. The announcement stays; the tree is gone when the forge is. Push objects to a GRASP remote (or import + Push on gittr). |
| nak / git-remote-nostr that actually pushed to a GRASP remote | Objects on that GRASP host plus the announcement | Same idea as a good gittr push: independent mirror, still findable. |
What to do now
Looking for a Nostr mirror of a known forge repo (GitHub, GitLab, Codeberg, Gitea, … — exact URL / owner/repo, not fuzzy name)? Use MCP findReposBySource or GET /api/nostr/repos-by-github?source=https://…— returns npub + gittr URL so you can reach them on Nostr (profile / DM) when the forge is unreachable. Needs a Push to Nostr announce that kept the source tag. Import / clone only copies repo objects (commits, trees, blobs) — not the old forge's server config. After Push, confirm a clone[] URL works without the original host. If you still run self-hosted Gitea older than 1.27.1, patch that machine separately: GHSA-6v53-hr58-556r, GHSA-rcr6-4jqh-j84m, Gitea 1.27.1.
SSH keys are only for laptop [email protected]. They are Nostr kind 52 events the bridge copies into authorized_keys. The website is not in the SSH path after the key is registered.
gn ssh-key add ~/.ssh/id_ed25519.pubPush to Nostr, issues, and PRs in the browser use your Nostr key, not SSH.
For complete documentation on SSH and Git operations:
📖 SSH & Git Access Guide (gittr) →📖 gitnostr bridge SSH guide →📖 gitnostr infrastructure (no git hook — SSH + relays) →Select code in any file viewer to share it as a standalone snippet on Nostr. The action bar appears near your selection with options to copy a permalink or share as a snippet.
Markdown anchors: In Markdown preview, headings show a link icon on hover. Click it to copy a direct heading link and update the URL hash for easy sharing.
Mobile-friendly: Line numbers are hidden on mobile devices to avoid alignment issues, but all functionality is preserved. Code lines remain fully clickable for selection.
Share code snippets from your repositories as standalone, discoverable events on Nostr.
How to Share:
What Gets Shared:
Reference code snippets in issue and PR comments. Snippets will appear inline with syntax highlighting.
💡 How it works:
nostr:note1... or hex format)Learn more about NIP-C0:
📖 NIP-C0 on gittr schemata →Zap a repository to tip the owner (and optionally split among contributors). Owner only resolves where the invoice is paid to using the priority below. When the LNURL-pay endpoint supports NIP-57, gittr requests a real zap invoice. Split mode mints the invoice from your LNbits wallet (repo payment config first, then Settings → Account) plus the SplitPayments extension — it does not rely on Nostr zap receipts for routing.
| Flow | Payer (sender) | Recipient / repo | How gittr confirms |
|---|---|---|---|
| Repo zap — Owner only | NIP-07 extension to sign a zap request when NIP-57 is available; any Lightning wallet to pay the invoice. Your LNbits / NWC send in Settings → Account is only for polling when gittr issued the invoice through the fallback server path. | Receive address priority: (1) owner Nostr kind 0 lud16 / lnurl / NWC receive, (2) if you are that owner, your Settings → Account receive fields, (3) else Repo → Payment configuration receive fields. LNURL must advertise allowsNostr for the NIP-57 path. | NIP-57: the page does not auto-detect your wallet; a kind 9735 receipt may appear in Your Zaps after relays gossip it. Fallback invoice (no NIP-57): same modal notice; LNbits keys in your account may allow polling when gittr created the invoice server-side. |
| Repo zap — Split | Send wallet priority: (1) Repo → Payment configuration LNbits URL + admin key if set, (2) otherwise Settings → Account. SplitPayments targets in that LNbits wallet must match contributor Lightning addresses. | Each included contributor needs a discoverable Lightning address (Nostr profile or linked identity). | LNbits invoice / wallet state — designed for reliable server-side settlement, not Nostr gossip latency. |
| Bounties | Bounty creator: LNbits URL + admin key in Settings → Account (creates withdraw links from that wallet). | PR author: Lightning address on their Nostr profile for claim payout. | LNbits withdraw link lifecycle (reserve, release, claim) — must stay fast and auditable on the server. |
| Pay-to-merge / push paywall | Payer uses the shown invoice; optional NWC / WebLN from Settings → Account. | Repo owner: keys under Repo → Payment configuration (and/or global account keys per push flow) so gittr / the bridge can verify settlement — see setup docs for the exact key types. | Server checks invoice / push policy — not NIP-57 receipts. |
Rows above describe what each flow needs, not every optional shortcut. Bounty creation always uses the bounty creator's keys from Settings → Account (not the repo's LNbits send configuration).
💬 Payment Messages:
All zaps and bounties automatically include a payment message with your username, "via gittr.space", and bolt emojis (⚡⚡). This helps recipients identify where the payment came from. The message format is: {username} via gittr.space ⚡⚡ (max 160 characters).
Anyone can fund issues with bounties to incentivize contributions. Bounties use LNURL-withdraw links created from the bounty creator's LNbits wallet. The funds are reserved in the creator's wallet and will be deducted when the PR author claims the withdraw link.
lud16 / lnurl) in Kind 0Visit the Bounty Hunt page to discover funded issues across all repositories.
Go to Settings → Notifications to set up:
/start, paste the User ID into Settings → Notifications. No public channel post required. You can enable Nostr and Telegram together.Save now does two things: publishes your toggles as a kind 30078 event (d=gittr/notifications) so prefs sync across browsers, and registers delivery on the server (Telegram User ID stays off public relays). DMs always use the recipient's saved prefs — not whoever clicked in their own browser.
Bounty announcements are also posted to the public @gittrspace channel (announcements only — not used for auth).
You can enable/disable notifications for:
Defaults: collaboration (new issues, issue comments, PRs, reviews, merges, mentions, bounties) is on; stars / watches / zaps are off; security (CVE) alerts stay off until you opt in.
Dependency notices are listed under Dependency notices (CVE).
Important: Changes to notification preferences are not active until you click "SAVE NOW". Make sure to save your preferences after making changes.
Supply-chain attacks on git forges are a hot topic. gittr scans the dependencies of every repo against the public OSV.dev vulnerability database and shows the result on the repo's Dependencies tab.
Exact matches only: an advisory is only reported as confirmed when the exact dependency version from your committed lockfile (package-lock.json, yarn.lock, Cargo.lock, go.mod, pinned requirements.txt, …) falls inside the version range the advisory declares as affected. Versions guessed from ranges in package.json are listed separately as unconfirmed and never trigger alarms.
How the message looks: Telegram / Nostr DMs lead with the repo name, list at most a few findings, and link to a tracking Issues entry on that repo — not a wall of hex URLs or truncated advisory dumps. Wording is deliberately calm: this is a dependency advisory notice, not a claim that the project is compromised.
How often does the check run? The audit runs fresh every time the Dependencies tab of a repo is opened — there is no fixed schedule. It reads the lockfiles from the pushed repo tip on gittr (the bridge clone), not from files only on your laptop or only on GitHub until those are synced here. Advisory details are cached on the server for about 6 hours, so a newly published CVE shows up within hours, at the latest on the next visit after the cache expires.
How alerts reach you (Dependabot-style): when a published CRITICAL or HIGH advisory matches a direct pinned dependency on a repo that has code on gittr (created / imported / pushed here — not merely announced from another client), the platform can open a normal Issues entry on that repo (for tracking) and notify you on the same channels you enabled (Nostr and/or Telegram). That entry is visible on the repo's Issues tab like any other issue — we avoid frightening “security incident” branding. A lockfile match still needs your check: whether your code actually uses the affected APIs. All notification toggles (including Security) live in one kind 30078 event (d=gittr/notifications) so they sync across browsers. Save also registers delivery on this server (Telegram User ID stays off public relays).
Your repos only — not watched / starred: Security scans the repos you own on gittr (your kind 30617 announcements), not projects you only watch, star, or follow. Watching someone else's stack is intentionally out of scope — noisy, permission-awkward, and easy to get wrong. If you want CVE / early-warning coverage of another project, fork or import it under your account so you own the tip on gittr, then keep Push in sync as usual.
Fresh tip only — keep announcement in line with source: the scanner reads lockfiles from the gittr bridge clone, but only when Nostr repo state (kind 30618) exactly matches that clone. No tip, or tip ≠ bridge → skip (no DM about the wrong tree). That match is what a successful Push from the gittr UI is supposed to publish. If you changed the repo on GitHub (or another forge) and want CVE coverage of that tip: bring it onto gittr (sync / refetch from source on the repo), then Push so the announcement lines up with the mirror. A browser-only file refresh without Push does not update the announcement. Same idea if you only update in another Nostr git client — Push/sync on gittr again when you want alerts here.
How notices are sent: when you are opted in, the platform bot opens a calm dependency-tracking Issues entry on that repo and DMs you (Nostr and/or Telegram per your prefs) for each new CRITICAL/HIGH lockfile match. The same advisory is not re-sent on later scans.
Early (pre-CVE) warnings — same opt-in: with Security enabled you also get private DMs when the public Vulnerability Spoiler Alert RSS flags a HIGH/CRITICAL finding that looks related to a direct dependency in that repo (often before a CVE exists). There is no extra checkbox. These tips are not shown on the Dependencies tab (that tab stays OSV/confirmed only), and we do not open a gittr Issues entry for them. If the Spoiler feed is unreachable, Dependencies + normal dependency notices keep working unchanged.
One alert per problem — not per scan: each advisory triggers at most one issue per package per repo. Repeated scans that find the same known vulnerability stay silent.
Get the most protection:
package==1.2.3 in requirements.txt).30618 matches the tip on gittr — otherwise CVE alerts stay skipped.Bounty notifications are sent to:
Bounty announcements are also automatically posted to the public @gittrspace Telegram channel, regardless of your notification preferences.
Think of three separate layers. Mixing them up is what causes confusion — not the UI itself.
| Layer | What it is | Where it lives |
|---|---|---|
| Forge Release | A tagged Release on GitHub / Codeberg / GitLab with real download files (APK, AppImage, MSI, checksums, …). Create those assets on the forge (or with their CLI / CI). | On that forge. gittr's Releases tab syncs and lists them when the repo has a matching source URL. The same tab also lists NIP-82 / Blossom releases from Nostr for GRASP-only repos (no forge required to read). |
| gittr "New release" | Optional notes / tag label in the browser for this repo. Does not upload binaries yet (Blossom upload is planned), and does not publish to /apps. | Local to your browser (per-repo storage). Useful as a memo; not a substitute for forge assets. |
| Nostr Apps announce | Owner-only, explicit step from the Code sidebar → Nostr Apps. Needs a forge Release with an .apk for Zapstore. Other verified platform files on the same tag can be linked as extra NIP-82 assets. You choose this — it never runs on ordinary Push to Nostr. | Signed events on Nostr relays (kinds 32267 app, 30063 release, 3063 asset). Shown on /apps, your profile Apps section, and optionally Zapstore. Download url still points at the forge unless you host elsewhere. |
If the forge later goes offline, mirrored source code (after Push) can still be cloned from GRASP — but release installers that only lived on the forge will not. Full table: When your git host goes dark.
Owners publish a static site from the repo Code sidebar → Nostr Pages: add a root entry file (for example index.html), keep the README Pages block in sync, Push to Nostr, then Push Manifest (uploads to Blossom and publishes kind 35128). Browse live sites at /pages.
gittr's gateway is adapted from hzrd146's nsite work — credit where it's due:
Owners list an Android app from the Code sidebar → Nostr Apps: link a GitHub / Codeberg / GitLab source URL, pick a Release that includes an .apk, verify the APK, then Publish on Nostr (NIP-82). Zapstore needs the APK; other binaries on the same Release tag (DMG, AppImage, MSI/EXE, …) can be linked as extra NIP-82 assets on that version. Files stay on the forge; gittr only announces. The repo Releases tab lists all forge download assets (not only APKs). How Releases, forge files, and announces fit together: Releases & where they live. Discover apps at /apps.
Optional Zapstore catalog: add zapstore.yaml at the source repo root, then publish again. Details:
Create PRs to propose changes. Reviewers can approve, request changes, or merge PRs. Repo owners editing their own Nostr / bridge repos on the Code tab can Save changes locally and use Push to Nostr — they do not need a PR.
Merge vs Close (what hits Nostr)
📋 How PRs Are Organized
Track bugs, feature requests, and discussions. Add bounties to incentivize solutions.
📋 How Issues Are Organized
Link your GitHub profile in Settings to show your profile picture as a contributor icon.
All your data (repos, keys, settings) is stored locally in your browser. It never leaves your device unless you explicitly push to Nostr.
⚠️ Browser & Domain Isolation
Your data is stored separately for each browser and domain:
If you're missing repos, PRs, or edits: They might be in a different browser or on a different domain. Use the Repos page to see all repositories from Nostr (consistent across browsers). Someone's profile lists their public Nostr announcements the same way whether you are signed in or not — opening one of their repos does not become their whole catalog.
Your Nostr private key and payment credentials are encrypted with a password you set. Enable encryption in Settings → Security.
Repositories default to public when pushed to Nostr. You can set them to private in repository settings.
If you have questions or hit issues, see the gittr source repo, plus gitnostr and gittr-helper-tools, and the Nostr schemata reference for NIPs and kinds.