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+ and pnpm 10+.
Start by creating a Neon project, then copy the pooled Postgres
connection string from the Neon dashboard. Keep it ready for the NUXT_DATABASE_URL
value in the env setup step below.
Next, open smee.io, create a new channel, and copy that URL.
This URL is the webhook destination GitHub should send to during local
development. If you do not have the CLI yet, install it with
pnpm add -g smee-client.
Then create a new GitHub App at
github.com/settings/apps/new. On the
creation form, set GitHub App name to any unique name, Homepage URL to your
local origin (http://127.0.0.1:3000), Callback URL to
http://127.0.0.1:3000/api/github/oauth/callback, Setup URL to
http://127.0.0.1:3000/connect, and enable "Redirect on update".
Keep user OAuth toggles at their defaults unless you specifically need them, but keep webhooks active and set Webhook URL to your Smee URL with a webhook secret you choose.
Set repository permissions to contents:read and metadata:read. For event
subscriptions, use push, create, delete, and repository.
If you do not see those event checkboxes yet, save the app after adding the
webhook URL, then return to the "Permissions & events" page and select them
there.
After creation, copy App ID, Client ID, generate a client secret, and generate
a private key (.pem) for the NUXT_GITHUB_APP_* values.
If you need to install this app in organizations/accounts other than the owner account, go to Advanced > Danger zone and make the app public.
Now create your local env file and fill all variables:
cp .env.example .env
Use these helpers for generated values:
pnpm gen:og-image-secret # NUXT_OG_IMAGE_SECRET
pnpm gen:jwk # NUXT_ATPROTO_PRIVATE_JWK
pnpm gen:encryption-key # NUXT_ENCRYPTION_KEY and NUXT_SESSION_PASSWORD
pnpm gen:cron-secret # CRON_SECRET
After .env is complete, install dependencies and run migrations:
corepack enable
pnpm install
pnpm db:migrate
Local development should run in three terminals:
# terminal 1
smee --url <your-smee-url> --target http://127.0.0.1:3000/api/github/webhook
# terminal 2
pnpm dev
# terminal 3
pnpm jobs:tick # run this to sync queued jobs while developing; Vercel Cron runs it in production
Deploy to Vercel #
synchub.to runs on Vercel with a Neon Postgres database.
- Apply migrations against your production database:
NUXT_DATABASE_URL="<pooled neon connection string>" pnpm db:migrate - Import the repo into Vercel (the Nuxt preset is auto-detected) and set every
variable from
.env.exampleunder 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. - Set
NUXT_PUBLIC_URLto your real origin, point the GitHub App webhook athttps://<your-domain>/api/github/webhook, and set the App's Setup + Callback URLs tohttps://<your-domain>/connectandhttps://<your-domain>/api/github/oauth/callback. - 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.