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".
Leave the user authorization toggles at their defaults, but do copy the Client
ID and generate a client secret: the Callback URL above drives a user-OAuth leg
that proves a connecting user administers the installation before any tangled
handle is bound to it, so NUXT_GITHUB_APP_CLIENT_ID and
NUXT_GITHUB_APP_CLIENT_SECRET are required, not optional. 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 install dependencies, which the secret-generation helpers below need:
corepack enable
pnpm install
Create your local env file and fill in every variable:
cp .env.example .env
Use these helpers for the generated values:
pnpm gen:jwk # NUXT_ATPROTO_PRIVATE_JWK
pnpm gen:encryption-key # NUXT_ENCRYPTION_KEY and NUXT_SESSION_PASSWORD
pnpm gen:cron-secret # CRON_SECRET
Once .env is complete, apply migrations:
pnpm db:migrate
Local development runs in three terminals. Proxy webhooks to your dev server:
smee --url <your-smee-url> --target http://127.0.0.1:3000/api/github/webhook
Run the app:
pnpm dev
And drain the job queue as needed while developing (Vercel Cron does this in production):
pnpm jobs:tick
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.