Help & Documentation

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.

What you can do on gittr
  • Mirror & backup — Copy repos from your server or a central forge to Nostr git relays (GRASP).
  • Issues & PRs on Nostr — Reviews, merge, and push updated repo state so other clients see the same tree.
  • Nostr Pages — Publish static sites from a repo (site file + README block + Push to Nostr / Blossom); browse the directory at /pages. Owner tools live in the Code sidebar under Nostr Pages . How-to: Publish Pages, Apps & Releases.
  • Nostr apps — Discover and install apps from /apps. Repo owners use the Code sidebar Nostr Apps panel to list an Android app from a GitHub / Codeberg / GitLab Release that has an .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.
  • Releases — The repo Releases tab shows forge download assets when a GitHub/Codeberg/GitLab source is linked, and also NIP-82 / Blossom releases from Nostr (same family as /apps). Creating or announcing a release is not the same as Push to Nostr. Details: Releases & where they live.
  • Bounties & zaps — Fund issues; pay contributors over Lightning (see Bounties below).
  • Import — One repo or bulk from GitHub/GitLab when you already host code elsewhere.
Getting Started
1. Login with NIP-07

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.

2. Create or Import a Repository

You can create a new repository or import from GitHub/GitLab/Codeberg. There are three ways to get started:

Option 1: Import single repository

Import an existing repository from GitHub, GitLab, or Codeberg:

  • Enter owner/repo (e.g. arbadacarbaYK/gittr)
  • Or a full URL: https://github.com/owner/repo
  • Files are fetched and stored in your browser
Option 2: Create empty repository
  • Enter a repository name
  • Click "Create Empty Repository"
  • You're taken to Upload — drag & drop files or folders, or use Choose files / Choose folder
  • Or push via Git CLI if you prefer (see below)
  • Reusing a name you deleted earlier is fine — gittr treats the new live announcement as current (My Repositories / Explore / profile catch up once the new Push is seen)
Option 3: Bulk import from GitHub

Load 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).

  • Open bulk import from New repository
  • Fetch Repos, tick what you want
  • Import only runs when you confirm selected (or Import All)
  • Optional: Also Push selected to Nostr on the bulk page; otherwise use Push to Nostr per repo later
Getting files into an empty repo

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:

  1. git clone [email protected]:<pubkey>/<repo>.git
  2. Add files in the clone
  3. git add . && git commit -m "Initial commit"
  4. git push origin main

Imported repos already include files in the UI. The bridge only shows committed/pushed trees for empty creates.

3. Set Up Payments (Optional)

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.

Install gittr as an App (PWA)

gittr is installable as a Progressive Web App (PWA) on modern browsers. This gives you an app icon, standalone window, and offline fallback page.

Desktop (Chrome/Edge/Brave)
  • Open gittr in your browser (HTTPS required).
  • Click the install icon in the address bar, or go to the menu → Install app.
  • Confirm to add gittr to your desktop/app launcher.
iOS (Safari)
  • Open gittr in Safari.
  • Tap Share → Add to Home Screen.
Android (Chrome/Brave)
  • Open gittr in Chrome or Brave.
  • Tap the menu → Install app.

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.

Managing Repositories
Creating Repositories

You can create repositories in three ways:

  • Import from GitHub/GitLab/Codeberg: Files are automatically fetched and stored in your browser
  • Create empty repository: Creates an empty repo that you must populate via Git CLI (clone, add files, commit, push)
  • MCP or gn: Agents use 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):

  1. Pick a git door: SSH (laptop, like GitHub) or HTTPS / MCP (agents — no SSH key)
  2. For SSH only: publish your public key once (Settings → SSH Keys, or gn ssh-key add). The website is not in the SSH path after that.
  3. Clone: git clone [email protected]:<your-npub>/<repo-name>.git or HTTPS https://git.gittr.space/<hex>/<repo>.git
  4. Add files: Copy files into the cloned directory or create new files
  5. Commit: git add . && git commit -m "Initial commit"
  6. Push: git push origin main

Files will appear in the web UI after pushing. See Git Operations section for detailed instructions.

Repository Status
  • Local - Only exists on your device
  • Pushing... - Currently being published to Nostr
  • Live on Nostr - Published and visible to others
  • Live (Unpushed Edits) - Has local changes not yet published
  • Push Failed - Publication attempt failed
Repo toolbar: Watch, Star, Zaps
  • Watch — publishes your NIP-51 kind 10018 followed-repos list (one replaceable event with the full a tag set each time).
  • Star NIP-25 kind 7 reaction on the repo's kind 30617 event. gittr looks that event up on your relays and on the same profile-repos query used to load files, Public/Private, Refetch, and new issues — a foreign GRASP clone still counts as published. The button stays Star while that lookup runs in the background (it should not flicker to “Looking up…”). A GitHub source that was deleted or made private is skipped — it must not stall the page. Also listed on your Stars page. Not the same as Watch.
  • Zaps — shortcut to tip; totals combine Nostr zap receipts and this device's ledger where relevant.
File Management

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.

File Sources & NIP-34 Architecture

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.

Importing Repositories

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.

  • GitHub — single repo or bulk import. Linking GitHub via NIP-39 under Settings → Profile matches GitHub usernames to npubs (contributor pictures). It is not what makes you the gittr owner: importing while logged in already does that. The purple owner pill on a profile is “this npub announced the repo,” not “GitHub confirmed.” A profile’s repository grid is that npub’s Nostr announcements (including Shakespeare/ngit), the same list whether you are logged in or not — not GitHub and not the few repos your browser already cached. Importing your own GitHub repo is still owner. The purple forked pill is only for a real upstream parent (someone else’s repo on any supported forge) or a gittr Fork — not “this has a forge URL.”
  • GitLab, Codeberg, Gitea / Forgejo, other HTTPS / git@ URLs — paste the full clone URL on Create repository (Option 1). The server runs a normal public 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.
  • Nostr-only / GRASP — paste 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).
Three ways gittr talks to forges

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.

Size limits

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.

Private repositories

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.

  • Only the owner and npubs listed under Settings → Contributors / maintainers can open private repos (web, SSH, HTTPS).
  • Being a GitHub maintainer is not enough until the owner adds your npub (or you are mapped via OAuth / NIP-39).
  • Private GitHub source files may still need GitHub OAuth (Settings → SSH Keys) while reading from GitHub itself.
  • SSH denial looks like permission denied for read operation— ask the owner to add your npub.
Git Operations
Clone a Repository

gittr.space repositories support multiple clone URL formats:

Option A: SSH (Standard Git - Recommended)

git clone [email protected]:npub1.../repo-name.git

For 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.git

Same 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-name

Requires git-remote-nostr. This helper translates nostr:// URLs into standard Git fetches and is used by other NIP-34 clients.

Install git-remote-nostr

  • macOS/Linux: pip install git-remote-nostr (Python 3.10+)
  • or build from source: github.com/aljazceru/git-remote-nostr
  • Add to PATH so Git can find the helper (verify with which git-remote-nostr)

How it works:

  • With SSH keys (added in Settings → SSH Keys): Automatically uses SSH for push/pull operations
  • Without SSH keys: Falls back to HTTPS (read-only or with credentials)

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.

Browsing files on the Code tab

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.

  1. Cache / small embedded files in the event (legacy)
  2. GitHub / GitLab / Codeberg when a source or GitHub clone URL exists
  3. For each GRASP HTTPS URL in clone[] (in parallel): read our on-disk mirror, or shallow-clone that URL directly, or mirror it onto gittr then read

If 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.

Supported Git Commands

Day-to-day

git pull / git fetchgit checkout <branch>git statusgit add / git commit

Publishing

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.3

Git 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 --oneline
Push to Nostr

After 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):

  • Announce — we sign a NIP‑34 event (name, description, clone links, etc.) and publish it to your relays. The event is mostly metadata, not your full Git history.
  • Mirror (gittr) — we also try to put a Git copy on 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)

  • Repo owners must configure either LNbits Invoice Key or Blink API Key in Settings -> Account before enabling non-zero Push Cost.
  • If a repo has Push Cost (sats) above zero, "Push to Nostr" first creates a payment invoice.
  • The UI shows a QR/BOLT11 invoice popup. Pay it with any Lightning wallet, then retry push.
  • For SSH pushes, if authorization is missing/expired the terminal may print a pending invoice (BOLT11) directly. Pay it, then run git push again.
  • Each paid authorization is single-use: one successful bridge push consumes it. Unused authorization expires after a short time.
Common push errors
  • 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.
When your git host goes dark

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.

PathWhat is storedIf that host dies or gets taken down
gittr import, never Push to NostrMostly 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 NostrKind 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 onlyMetadata on Nostr pointing at the original forgeNot 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 remoteObjects on that GRASP host plus the announcementSame idea as a good gittr push: independent mirror, still findable.

What to do now

  • Source still reachable? Import it into gittr while you can (Importing Repositories, or Create repository and paste the clone URL), then Push to Nostr.
  • Only a local backup / disk copy left? Create a new repo from that tree on /new, then Push to Nostr so others can clone without the old host.

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

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.

  • Optional UI: Settings → SSH Keys. Kind 52 is signed with NIP-07, Amber / NIP-46 (bunker), or nsec — not only a browser extension.
  • CLI, no UI: gn ssh-key add ~/.ssh/id_ed25519.pub
  • Agents: gittr-mcp uses HTTPS + nsec instead — skip SSH entirely

Push to Nostr, issues, and PRs in the browser use your Nostr key, not SSH.

Code Snippets (NIP-C0)

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

Share code snippets from your repositories as standalone, discoverable events on Nostr.

How to Share:

  1. Open any file in a repository
  2. Select the code lines you want to share (click to select, Shift+click to extend)
  3. Click the "Share as snippet" button that appears
  4. Optionally add a description
  5. Click "Share to Nostr"

What Gets Shared:

  • The selected code (with syntax highlighting)
  • Language and file extension (auto-detected)
  • Optional description
  • Link back to source repository (NIP-34 format)
Using Snippets in Comments

Reference code snippets in issue and PR comments. Snippets will appear inline with syntax highlighting.

💡 How it works:

  1. Share a code snippet using the "Share as snippet" button
  2. Copy the snippet event ID (shown after sharing)
  3. Paste the event ID in a comment (as nostr:note1... or hex format)
  4. The snippet will automatically render inline with syntax highlighting
Snippet Features
  • Syntax Highlighting: Code is displayed with proper formatting
  • Copy Code: One-click copy button
  • Download: Download snippet as a file
  • Repository Link: Click to view the source repository
  • Discoverable: Snippets are searchable across the Nostr network

Learn more about NIP-C0:

📖 NIP-C0 on gittr schemata →
Payments & Bounties
Zaps

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.

FlowPayer (sender)Recipient / repoHow gittr confirms
Repo zap — Owner onlyNIP-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 — SplitSend 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.
BountiesBounty 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 paywallPayer 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).

  • Zaps: The message is included in the invoice comment field (visible to the recipient)
  • Bounties: The message is included in the withdraw link title (visible when claiming the bounty)
  • Your username is automatically fetched from your Nostr profile (Kind 0 metadata)
Bounties

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.

Requirements
  • Creator: LNbits sending wallet in Settings → Account, with balance until claim
  • PR author: Nostr pubkey + Lightning address (lud16 / lnurl) in Kind 0
Bounty flow (steps)
  1. Create bounty on an issue (prompts for LNbits if missing)
  2. LNURL-withdraw link reserves funds in the creator wallet
  3. Developer opens a PR linked to the issue
  4. Repo owner merges → withdraw link released to PR author
  5. PR author claims → sats leave creator wallet to their Lightning address
  6. Issue closed without PR → withdraw link deleted, bounty cancelled
Protection & trust model
  • Linked PR blocks bounty deletion even if the issue closes
  • Merging attests the fix — only create bounties on repos you trust
  • Closed without PR cancels the bounty; creator is notified
Flow diagram
Statuses & key points
  • Pending / Paid / Released / Cancelled / Offline
  • Funds stay in the creator wallet until claim (withdraw links, not instant send)
  • Claim needs the PR author's Lightning address on Nostr
Bounty Hunt

Visit the Bounty Hunt page to discover funded issues across all repositories.

Notifications
Configure Notifications

Go to Settings → Notifications to set up:

  • Nostr DMs - Receive encrypted direct messages on Nostr
  • Telegram - Private DMs via @gittrupdatebot: send /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).

Notification Events

You can enable/disable notifications for:

  • New issue in watched repos - When someone opens an issue in a repository you're watching
  • Comments on issues I opened/participate - When someone comments on an issue you created or are assigned to
  • New pull request in watched repos - When someone opens a PR in a repository you're watching
  • Reviews requested or comments on my PRs - When someone requests your review or comments on your PR
  • My PR merged - When your pull request is merged
  • I am @mentioned - When someone mentions you in a comment or description
  • My Bounties - When a bounty is funded on an issue you created (you'll be notified about the bounty amount)
  • Bounty released to me - When a bounty withdraw link is released to you after a PR you created is merged

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.

Dependency notices (CVE) — calm by design, verify before panic

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:

  • Commit your lockfiles. Without them, exact versions can't be verified and you only get unconfirmed hints.
  • Pin versions where your ecosystem supports it (e.g. package==1.2.3 in requirements.txt).
  • Opt in and Save in Settings → Notifications so consent is on relays — localStorage alone is not enough for the bot.
  • Keep Push / announcement current. After dependency or tip changes on GitHub (or on gittr), sync from source if needed, then Push so kind 30618 matches the tip on gittr — otherwise CVE alerts stay skipped.
  • Check the Dependencies tab after importing a repo and after dependency updates are on gittr.
  • Update affected packages to a version outside the advisory's affected range, then get that new lockfile onto gittr before re-checking the tab: Nostr/git push if you fixed it locally, or sync from the source forge + Push if you fixed it there. Opening the tab alone does not see unpushed or unsynced changes.
Bounty Notifications

Bounty notifications are sent to:

  • Issue Owner (My Bounties): When someone funds a bounty on your issue, you'll receive a notification via Nostr DM and/or Telegram (if enabled) with the bounty amount and issue details.
  • PR Author (Bounty released to me): When a PR you created is merged and linked to an issue with a bounty, you'll receive a notification that the bounty withdraw link has been released to you. The notification includes the bounty amount and instructions on how to claim it.
  • Bounty Creator (Bounty cancelled): When an issue with your bounty is closed without a PR, you'll receive a notification that the bounty was cancelled and the withdraw link was deleted. This helps you know that your funds are no longer reserved.

Bounty announcements are also automatically posted to the public @gittrspace Telegram channel, regardless of your notification preferences.

Publish Pages, Apps & Releases
Releases & where they live

Think of three separate layers. Mixing them up is what causes confusion — not the UI itself.

LayerWhat it isWhere it lives
Forge ReleaseA 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 announceOwner-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.
Suggested flow
  1. Publish installers on the forge Release for that tag (CI or manual upload).
  2. Open the repo on gittr → Releases — assets should appear after a soft refresh from the forge.
  3. (Optional) On that forge tag, click Announce on Nostr (same Zapstore rules as Code sidebar → Nostr Apps): verify APK → Publish on Nostr for /apps / Zapstore.
  4. Prefer a new version / tag when binaries change. Re-announce the same version only to fix a bad listing.

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.

Nostr Pages (static sites)

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:

Nostr Apps & Zapstore

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:

Collaboration
Pull Requests

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)

  • Merge: applies the PR files and pushes the updated tip to Nostr / the bridge (same idea as Code-tab Push to Nostr). Other clients can see the new files after merge. You do not need an extra Push to Nostr afterward when that push succeeds.
  • Close (without merging): publishes a NIP-34 closed status event to relays so other git Nostr clients see it closed. It does not change files and does not need Code-tab Push to Nostr (that is for repo files / tip). Use Close to drop an unwanted PR.
  • Reopen: publishes open status to Nostr — still no file / tip push.

📋 How PRs Are Organized

  • Sorted by creation time: PRs are displayed with the newest first, regardless of status changes
  • Aggregated from Nostr: PRs created by anyone (locally or on other clients) appear in the list automatically
  • Status tracking: Status changes (open → merged/closed) don't affect the chronological order
  • Real-time updates: New PRs and status changes from Nostr relays appear automatically
Issues

Track bugs, feature requests, and discussions. Add bounties to incentivize solutions.

📋 How Issues Are Organized

  • Sorted by creation time: Issues are displayed with the newest first, regardless of status changes
  • Aggregated from Nostr: Issues created by anyone (locally or on other clients) appear in the list automatically
  • Status tracking: Status changes (open → closed) don't affect the chronological order
  • Real-time updates: New issues and status changes from Nostr relays appear automatically
Contributors

Link your GitHub profile in Settings to show your profile picture as a contributor icon.

Security & Privacy
Local Storage

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:

  • Different browsers (Chrome, Brave, Firefox) have separate storage
  • Different domains (localhost:3000 vs gittr.space) have separate storage
  • Repos, PRs, Issues, and edits are not shared between browsers/domains

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.

Encrypted Keys

Your Nostr private key and payment credentials are encrypted with a password you set. Enable encryption in Settings → Security.

Public vs Private

Repositories default to public when pushed to Nostr. You can set them to private in repository settings.

Additional Resources
Documentation
Need More Help?

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.