mirror your GitHub repos to tangled.org automatically
1

Configure Feed

Select the types of activity you want to include in your feed.

41 1 0

Clone this repository

https://tangled.org/danielroe.dev/synchub.to https://tangled.org/did:plc:g4lh56ouiwlcyhukzkjvy75g
git@tangled.org:danielroe.dev/synchub.to git@tangled.org:did:plc:g4lh56ouiwlcyhukzkjvy75g

For self-hosted knots, clone URLs may differ based on your setup.



README.md

synchub.to#

mirror your GitHub repos to tangled.org automatically.

Install the GitHub App, connect your tangled identity, and every commit, branch, and tag will be mirrored to tangled.

Features#

  • no workflow file required
  • one-time OAuth connection to tangled
  • per-push sync of branches and tags
  • a dashboard where you can resync, pause, or rotate keys
IMPORTANT

Only public repositories are synced (tangled does not yet support private repositories).

Run it locally#

You will need Node 24+, pnpm 10+ (corepack enable), a Neon database (free tier is fine), and the Smee CLI for webhook proxying (pnpm add -g smee-client).

corepack enable
pnpm install
cp .env.example .env   # fill in the values, see below
pnpm db:migrate
pnpm dev

.env.example documents every variable. Generate the secrets with the bundled helpers:

pnpm gen:jwk              # NUXT_ATPROTO_PRIVATE_JWK
pnpm gen:encryption-key   # NUXT_ENCRYPTION_KEY and NUXT_SESSION_PASSWORD
pnpm gen:cron-secret      # CRON_SECRET

The rest (NUXT_DATABASE_URL, the NUXT_GITHUB_APP_* values) come from your Neon dashboard and a new GitHub App. The App needs contents:read and metadata:read permissions plus the push, create, delete, and repository events, with its webhook pointed at your Smee URL. Set the Setup URL to <origin>/connect (tick Redirect on update) and the Callback URL to <origin>/api/github/oauth/callback; the latter drives the user-OAuth that verifies a connecting user administers the installation before any handle is bound. Copy the App's Client ID and a generated client secret into NUXT_GITHUB_APP_CLIENT_ID / NUXT_GITHUB_APP_CLIENT_SECRET.

In separate terminals, proxy webhooks and drain the job queue:

smee --url <your-smee-url> --target http://127.0.0.1:3000/api/github/webhook
pnpm jobs:tick   # run as needed; in production Vercel Cron does this

Deploy to Vercel#

synchub.to runs on Vercel with a Neon Postgres database.

  1. Apply migrations against your production database:
    NUXT_DATABASE_URL="<pooled neon connection string>" pnpm db:migrate
    
  2. Import the repo into Vercel (the Nuxt preset is auto-detected) and set every variable from .env.example under Settings > Environment Variables. Mark the secrets (NUXT_DATABASE_URL, NUXT_GITHUB_APP_PRIVATE_KEY, NUXT_GITHUB_APP_CLIENT_SECRET, NUXT_ATPROTO_PRIVATE_JWK, NUXT_ENCRYPTION_KEY, NUXT_SESSION_PASSWORD, NUXT_GITHUB_WEBHOOK_SECRET, CRON_SECRET) as Sensitive.
  3. Set NUXT_PUBLIC_URL to your real origin, point the GitHub App webhook at https://<your-domain>/api/github/webhook, and set the App's Setup + Callback URLs to https://<your-domain>/connect and https://<your-domain>/api/github/oauth/callback.
  4. Deploy.

The worker runs on a Vercel Cron (declared in nuxt.config.ts, so no vercel.json is needed) and appears under Settings > Cron Jobs after the first deploy.

NOTE

The GitHub App private key is multi-line, but Vercel env values are single line. Collapse the newlines to literal \n before pasting:

awk 'NF {printf "%s\\n", $0}' your-app.private-key.pem

Locally, keep the real newlines as shown in .env.example. Migrations are manual: re-run pnpm db:migrate against production whenever you ship a schema change.

License#

Made with ❤️

Published under MIT License.