Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1f85e48
Add standalone bridge docs
arbadacarbaYK Nov 27, 2025
5e1e8ec
Document file fetch flow
arbadacarbaYK Nov 27, 2025
270ad96
Document fork-only enhancements
arbadacarbaYK Nov 27, 2025
2280115
Clarify supported NIPs and Blossom cloning
arbadacarbaYK Nov 27, 2025
ec3345f
Clean docs and add gittr reference
arbadacarbaYK Nov 27, 2025
212f9bd
Update README.md
arbadacarbaYK Nov 27, 2025
044143d
Add comprehensive platform-wide enhancements diagram
arbadacarbaYK Nov 30, 2025
6a3ea1b
Update documentation to match main gittr repo
arbadacarbaYK Nov 30, 2025
ae59f40
Sync updates from gittr main repo
arbadacarbaYK Dec 2, 2025
69f3e88
Improve bridge enhancements diagram clarity
arbadacarbaYK Dec 2, 2025
aece9c5
Clarify deduplication channel description
arbadacarbaYK Dec 2, 2025
51387ee
docs: Update file-fetch-flow with push process details
arbadacarbaYK Dec 5, 2025
fc63acf
docs: Add kind 30618 (Repository State) to supported NIPs & Kinds
arbadacarbaYK Dec 5, 2025
041a0f3
Fix broken relative links in documentation
arbadacarbaYK Dec 9, 2025
ce48d2a
Improve SSH git operations: better error messages and empty repo hand…
arbadacarbaYK Dec 12, 2025
6cc9f1a
Sync enhanced bridge features from gittr: HTTP fast lane, deduplicati…
arbadacarbaYK Dec 17, 2025
ac318f7
Update file-fetch-flow.md: note GitLab pagination requirement
arbadacarbaYK Dec 17, 2025
8cf98c4
Update GitHub link to gittr.space link in file-fetch-flow.md
arbadacarbaYK Dec 17, 2025
03eb3ef
Add state event handling with commit SHA validation and HEAD fallback
arbadacarbaYK Dec 19, 2025
df5fbf0
docs: Document empty commit file preservation in push process
arbadacarbaYK Dec 19, 2025
3448eb3
docs: Use 'other clients' instead of specific client name
arbadacarbaYK Dec 19, 2025
27cd775
Add SSH guide with create/add and modify workflows
arbadacarbaYK Dec 23, 2025
40c6825
Update SSH guide with private repo access information
arbadacarbaYK Dec 28, 2025
0585a28
Remove non-spec public-read/public-write from NIP-34 events
arbadacarbaYK Dec 28, 2025
b8377eb
Docs: Add UTF-8 file path encoding guidance for bridge API
arbadacarbaYK Dec 29, 2025
57716a4
Docs: Update README with NIP-34 compliance (kinds 1111, 1617-1633, 10…
arbadacarbaYK Jan 4, 2026
2c557d8
feat: extend ssh paywall messaging and auth handling
arbadacarbaYK Apr 30, 2026
a9f9c8e
fix owner ssh write access fallback
arbadacarbaYK Apr 30, 2026
30a4913
docs: canonical clone URL arbadacarbaYK/gitnostr; spearson78 as upstr…
arbadacarbaYK May 8, 2026
6695576
docs: clarify NIP-46 is client-side only; link gittr NIP-46 guides
arbadacarbaYK May 8, 2026
719eb8f
sync: mirror bridge and CLI from gittr embedded ui/gitnostr
arbadacarbaYK May 9, 2026
fc01c93
docs: file-fetch-flow matches gittr files API and empty-tree clone
arbadacarbaYK May 10, 2026
35a8ff9
sync: mirror bridge and git-nostr-ssh from gittr embedded ui/gitnostr
arbadacarbaYK May 14, 2026
3123ab6
docs: clarify gitnostr fork vs ngit and gittr ngit folder naming
arbadacarbaYK May 14, 2026
c83b2bb
Document gittr GRASP shallow-clone path alongside bridge mirror flow.
arbadacarbaYK May 20, 2026
9b567ca
docs: align README with gittr ngit comparison; add GitHub About text
arbadacarbaYK May 22, 2026
9dc9318
docs: rephrase GitHub About — positive framing vs ngit
arbadacarbaYK May 22, 2026
5b7b480
docs: add when-to-use section with concrete use cases
arbadacarbaYK May 22, 2026
d4bedb1
docs: update GitHub About — gittr stack features in description
arbadacarbaYK May 22, 2026
ac97d73
docs: refresh file-fetch-flow for shared branch and per-tab APIs
arbadacarbaYK May 22, 2026
41fc088
chore: remove REPO_DESCRIPTION.txt (About is GitHub settings only)
arbadacarbaYK May 22, 2026
708ab49
docs: SSH is bridge-native; gn/nostr:// not UI-only
arbadacarbaYK May 22, 2026
3f4be80
docs: fix HTTPS clone host in SSH guide
arbadacarbaYK May 22, 2026
955d4e9
docs: clarify git-nostr-hook unshipped; fix relay testing claims
arbadacarbaYK May 22, 2026
6ebb21e
docs: fix stale PR/issues paragraph; annotate architecture diagram
arbadacarbaYK May 22, 2026
75e8757
docs: describe only what exists; remove hook and negative disclaimers
arbadacarbaYK May 22, 2026
3ba9e6e
docs: simplify relay prerequisite line
arbadacarbaYK May 22, 2026
77d9bbb
docs: remove outdated bridge API and upstream framing
arbadacarbaYK May 22, 2026
e11670e
docs: link our repos on gittr.space instead of GitHub
arbadacarbaYK May 22, 2026
77efeb0
docs: replace hook diagram with current infrastructure overview
arbadacarbaYK May 22, 2026
059b431
docs: replace hook diagram; link nostr schemata on gittr
arbadacarbaYK May 22, 2026
dcb1ce0
docs: use gittr.space npub URLs for cross-repo links
arbadacarbaYK May 24, 2026
f2c6a33
docs: link gittr-mcp in ecosystem and client access paths
arbadacarbaYK May 24, 2026
4b37011
Sync bridge from gittr ui/gitnostr (private-repo + SSH fixes).
ArBaDaCarBa Jul 18, 2026
d53ef16
docs: add platform map with you-are-here on git.gittr.space
Jul 26, 2026
f0620a6
docs: add platform-map.svg so the map shows without Mermaid
Jul 26, 2026
c8448c8
docs: platform table links pyramid and gittr-mcp on gittr.space
ArBaDaCarBa Jul 26, 2026
3bcd922
fix(bridge): fetch missing commits on state events and register upstr…
arbadacarbaYK Jul 29, 2026
455eda7
fix: bump golang.org/x/sys 0.1.0 -> 0.47.0 (clears OSV advisory)
arbadacarbaYK Aug 8, 2026
cb42c9a
sync: public bridge tree from gittr ui/gitnostr (Aug 2026)
arbadacarbaYK Aug 17, 2026
acd49fe
docs: SSH is laptop git; MCP uses HTTPS, not the website.
arbadacarbaYK Aug 18, 2026
27e5f1a
docs: website signing is NIP-07 or NIP-46 remote (Amber), not only an…
arbadacarbaYK Aug 18, 2026
f769896
fix: GRASP retention — bare only if clone lists this host
arbadacarbaYK Aug 21, 2026
9c05331
docs: gittr repo/files 404 is expected for foreign clone hosts
arbadacarbaYK Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Use the official Go image as a base
FROM golang:latest

# Set the working directory
WORKDIR /usr/gitnostr

# Copy the source code
COPY . .

# Install openssh-server
RUN apt-get update && apt-get install -y openssh-server

# Generate a new SSH key for the root user
RUN ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ''

# Allow root login via SSH
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# Build the binary
RUN CGO_ENABLED=0 go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/git-nostr-bridge ./cmd/git-nostr-bridge
RUN CGO_ENABLED=0 go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/git-nostr-ssh ./cmd/git-nostr-ssh
RUN CGO_ENABLED=0 go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/gn ./cmd/git-nostr-cli

# Create config
RUN mkdir -p /root/.config/git-nostr

# Configure git-nostr-bridge
# Replace gitRepoOwners key with your public key (hex)
RUN echo '{"repositoryDir": "/root/git-nostr-repositories","DbFile": "/root/.config/git-nostr/git-nostr-db.sqlite","relays": ["wss://relay.gittr.space", "wss://relay.damus.io", "wss://nos.lol", "wss://relay.primal.net"],"gitRepoOwners": ["d7a2565a3d29c05a72c315c9117594bb0c76eda7ebfdda3441d0eb6ba326c5e1"]}' > /root/.config/git-nostr/git-nostr-bridge.json

# Set the default command to run when the container starts
CMD service ssh start && /usr/gitnostr/bin/git-nostr-bridge -config=/root/.config/git-nostr/git-nostr-bridge.json
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,13 @@ git-nostr-bridge:
git-nostr-cli:
go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/gn ./cmd/git-nostr-cli

.PHONY: migrate-npub-symlinks
migrate-npub-symlinks:
go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/migrate-npub-symlinks ./cmd/migrate-npub-symlinks

.PHONY: migrate-commit-dates
migrate-commit-dates:
go build -tags netgo -ldflags="-s -w" -trimpath -o ./bin/migrate-commit-dates ./cmd/migrate-commit-dates

.PHONY: all
all: git-nostr-bridge git-nostr-cli
all: git-nostr-bridge git-nostr-cli migrate-npub-symlinks migrate-commit-dates
221 changes: 51 additions & 170 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,188 +1,69 @@
# Nostr Git
# gitnostr

A proof of concept integration of git and nostr providing
**Git bridge to Nostr** for [gittr](https://gittr.space). Same codebase as **[arbadacarbaYK/gitnostr](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?branch=main)** on gittr.

- repository management
- ssh-key management
- repository permission management
**Components:** `git-nostr-bridge` · `git-nostr-ssh` · `git-nostr-db` · `git-nostr-cli` (`gn`)

This will hopefully form part of a solution for creating a decentralized version of the github/gitlab experience.
## Where this sits (platform map)

I chose to build on top of the existing git tooling to allow the client side dev tools to remain largely unchanged for daily work (standard git commands work including push and pull)
This repo is the **git server layer** — not the website and not the AI tools. **You are here = gitnostr Bridge** (`git.gittr.space`, teal). Cyan-outlined host boxes = public hostnames (teal = this repo; cyan outline = host URLs).

By storing the config on Nostr your repository configuration can be easily regenerated a new host if your current git provider decides to censor you.
![Platform map: gitnostr Bridge at git.gittr.space](docs/platform-map.svg)

See a demo video here: https://www.youtube.com/watch?v=G-WzlC8XfW4
```mermaid
flowchart LR
UI["gittr Client<br/>gittr.space"]
MCP["gittr-mcp<br/>AI agents"]
CLI["git / gn / SSH"]
Bridge["★ YOU ARE HERE · gitnostr Bridge<br/>git.gittr.space<br/>SSH / HTTPS · bare repos"]
RelayGittr["gittr Pyramid relay<br/>relay.gittr.space<br/>wss · open forge + GRASP"]
Relays["Other Nostr relays"]
Pages["Pages / nsite<br/>pages.gittr.space"]
Blossom["Blossom<br/>blossom.gittr.space"]
Remote["git remote nostr<br/>optional · ngit"]

There is much more to a decentralized github/gitlab experience than just a repository. It would also be advantageous to move pull requests and issues to the Nostr protocol. These should however be treated as separate projects that will hopefully be interopable with this project's approach to repository management.


# How

![Architecture diagram](git-nostr.png)

## git-nostr-db

An sqlite DB is used to cache the latest version of the data needed to perform access control checks to avoid development downtime in case of a relay or the git-nostr-bridge being offline.

### git-nostr-bridge

Connects to a set of relays and:
1. subscribes to the events needed to keep the git-nostr-db up to date
2. creates git repositories as needed
3. updates the ssh authorized_keys file

**DO NOT RUN THE BRIDGE AS YOUR OWN USER YOU WILL LOSE YOUR AUTHORIZED_KEYS FILE**

### git-nostr-ssh

Configured as the command for a nostr users ssh-key in the authorized_keys file.
Whenever a user tries to perform a git operation (push/pull) git-nostr-ssh will perform an access control check.

### git-nostr-hook

TODO: not implemented yet.

Will enable fine grain branch control e.g. prevent pushing to specific branches or force pushing to a branch.

### git-nostr-cli (gn)

Command line tool with similar options to the github cli that will publish the relevant events using your private key to the configured relays

git-nostr-bridge will then react to these events and update the DB and create any git repos needed.


# Setup Instructions

**Currently this project is Linux only**
**Go version 1.20+ is required**
**It is recommended to use a local private relay for testing. Testing was performed using https://github.com/scsibug/nostr-rs-relay**

## git-nostr-bridge

**These instructions are needed if you intend to host git repositories. If another nostr user has configured a git-nostr-bridge for you then follwo the git-nostr-cli instructions below.**

Create a new user to host the git repositories (This is needed as the bridge will overwrite the authroized_keys file) and switch to the new account

**DO NOT RUN THE BRIDGE AS YOUR OWN USER YOU WILL LOSE YOUR AUTHORIZED_KEYS FILE**

```bash
sudo useradd --create-home git-nostr
sudo su - git-nostr
```

Clone the gitnostr repository and build the bridge components

```bash
git clone https://github.com/spearson78/gitnostr
cd gitnostr
make git-nostr-bridge
```

Start the bridge once to create the empty config files. **DO NOT RUN THE BRIDGE AS YOUR OWN USER YOU WILL LOSE YOUR AUTHORIZED_KEYS FILE**

```bash
./bin/git-nostr-bridge
```

You should get the message `no relays connected`

Edit the config file at `~/.config/git-nostr/git-nostr-bridge.json`. The default file should look like this
UI -->|announce · push UI| RelayGittr
UI -->|announce · push UI| Relays
UI -->|import / sync| Bridge
UI -->|Pages blobs| Blossom
MCP -->|HTTP + Nostr auth| Bridge
MCP --> RelayGittr
MCP --> Relays
CLI -->|SSH / HTTPS git| Bridge
Bridge -->|watch kinds · bare repos| RelayGittr
Bridge -->|watch kinds · bare repos| Relays
Pages -.->|sites, not git objects| Relays
Pages --> Blossom
Remote -.->|same NIP-34 events| Relays

```
{
"repositoryDir": "~/git-nostr-repositories",
"DbFile": "~/.config/git-nostr/git-nostr-db.sqlite",
"relays": [],
"gitRepoOwners": []
}
```

Add your relay of relays to the list of relays. **You should use a local relay for testing until the implementation is finalized.**
Add your public key to the list of gitRepoOwners. **It is recommended to generate a new nostr private/public key pair for testing**

git-nostr-bridge will follow events published by gitRepoOwners and create git repositories for them.

My local testing config looks like this

```
{
"repositoryDir": "~/git-nostr-repositories",
"DbFile": "~/.config/git-nostr/git-nostr-db.sqlite",
"relays": ["ws://localhost:8080"],
"gitRepoOwners": ["e0e7807d354ea7662412d99856335e1923b0b57b6668575bf320837f6b1816e3"]
}
```

You can now start the bridge again. **DO NOT RUN THE BRIDGE AS YOUR OWN USER YOU WILL LOSE YOUR AUTHORIZED_KEYS FILE**

```bash
./bin/git-nostr-bridge
```

As no events have been published you should see no console output.

Your git-nostr-bridge is now ready for use

## git-nostr-cli (gn)

**Watch out for a conflict with the gn command from https://gn.googlesource.com **

Clone the gitnostr repository and build the cli components

```bash
git clone https://github.com/spearson78/gitnostr
cd gitnostr
make git-nostr-cli
```

run the git-nostr-cli command once to create the default config file

```bash
./bin/gn
```

You should get the message `no relays connected`

Edit the config file at `~/.config/git-nostr/git-nostr-cli.json`. The default file should look like this

```
{
"relays": [],
"privateKey": "",
"gitSshBase": ""
}
classDef youAreHere fill:#0f766e,stroke:#5eead4,stroke-width:3px,color:#ecfdf5
classDef hostUrl fill:#164e63,stroke:#22d3ee,stroke-width:2px,color:#ecfeff
class Bridge youAreHere
class Pages,Blossom,RelayGittr hostUrl
```

Add your relay of relays to the list of relays. **You should use a local relay for testing until the implementation is finalized.**
Set your private key. **It is recommended to generate a new nostr private key for testing**
Set gitSshBase to the ssh user@hostname where a git-nostr-bridge has been installed.
| Piece | Host / on gittr | Talks to this bridge how? |
| --- | --- | --- |
| **gittr Client** | [gittr](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gittr?branch=main) · `gittr.space` | Push/import → bridge API; clone URLs point at **`git.gittr.space`** |
| **★ gitnostr (this README)** | [gitnostr](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?branch=main) · **`git.gittr.space`** | **You are here** — bare repos, SSH keys (kind 52), permissions |
| **gittr-mcp** | [gittr-mcp](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gittr-mcp) | Agents push/list via HTTPS + signed Nostr headers |
| **Pages / nsite** | [nsite-gateway](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/nsite-gateway) · **`pages.gittr.space`** | Separate — static sites from Nostr, not the git object store |
| **Blossom** | **`blossom.gittr.space`** | Blob store used by Pages (and related media) — not git objects |
| **gittr Pyramid relay** | [pyramid](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/pyramid) · **`relay.gittr.space`** | Open `wss://` forge relay the bridge also watches |
| **gittr-helper-tools** | [gittr-helper-tools](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gittr-helper-tools?branch=main) | Snippets only — not a runtime host (omitted from the diagram) |
| **git remote nostr** | [ngit-cli](https://github.com/DanConwayDev/ngit-cli) | Optional; reads/writes same relay events; may also hit `clone` HTTPS |

My local testing config looks like this
**Addressing:** on disk, owner dirs are **hex pubkey**; HTTPS clone tags use **npub** via `npub → hex` symlinks on **`git.gittr.space`** (NIP-34-friendly). SSH accepts hex or npub.

```
{
"relays": ["ws://localhost:8080"],
"privateKey": "...",
"gitSshBase": "git-str@localhost"
}
```
Deeper internals: [Architecture](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?file=docs/ARCHITECTURE.md&branch=main) (more detailed than this map).

Publish your ssh-key. you may need to replace id_rsa.pub with the correct public key file
**Docs on gittr:** [Architecture](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?file=docs/ARCHITECTURE.md&branch=main) · [README](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?branch=main) · [SSH guide](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gitnostr?file=SSH_GIT_GUIDE.md&branch=main)

```bash
./bin/gn ssh-key add ~/.ssh/id_rsa.pub
```

Create a test repository and clone it. replace <publickey> with the hex represenation of your public key. If you are using a nip05 capable public key you can use the nip05 identifier instead.

```bash
./bin/gn repo create test
./bin/gn repo clone <publickey>:test
```
**gittr forge:** [arbadacarbaYK/gittr](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gittr?branch=main) · [bridge setup](https://gittr.space/npub1n2ph08n4pqz4d3jk6n2p35p2f4ldhc5g5tu7dhftfpueajf4rpxqfjhzmc/gittr?file=docs/GIT_NOSTR_BRIDGE_SETUP.md&branch=main)

You can set write permission for your repository with the following command. replace <publickey> with the hex represenation of your public key. If you are using a nip05 capable public key you can use the nip05 identifier instead.
**Build here (monorepo):**

```bash
./bin/gn repo permissions test <publickey> WRITE
make git-nostr-bridge git-nostr-ssh
make git-nostr-cli # gn
```
Loading