What this guide does
Use this guide when you want to wire SelfTune Cloud to GitHub so a repository can publish into the registry through the GitHub App flow.
This guide covers:
- Creating the GitHub App
- Wiring SelfTune environment variables
- Applying the required migration
- Binding an installation in the dashboard
- Verifying manual sync and webhook publishing
SelfTune can publish from GitHub by default. If you also grant Checks and
Commit statuses permissions, it can post publish results back to GitHub as
check-runs and commit statuses. It still does not open pull requests, create
releases, or push commits back to your repo.
Prerequisites
- A deployed SelfTune API reachable from GitHub webhooks
- A deployed SelfTune dashboard reachable by users after GitHub App installation
- A Pro-or-higher SelfTune org
- A GitHub account or GitHub organization where you can install apps
- A registry entry you want to publish into, or permission to create one
You also need the GitHub migration applied:
drizzle/0017_github_registry_foundation.sql
drizzle/0018_github_write_back.sql
Architecture
GitHub App install -> dashboard callback -> bind installation to org
GitHub push/tag webhook -> SelfTune API -> package repo -> push registry version
Dashboard/manual sync -> SelfTune API -> fetch repo -> push registry version
Step 1: Register the GitHub App
Create a GitHub App in GitHub settings and use these values.
| Setting | Value |
|---|
| App name | Your production app name, for example SelfTune Cloud |
| Homepage URL | Your dashboard base URL, for example https://selftune.dev |
| Setup URL | https://selftune.dev/settings/github |
| Webhook URL | https://api.selftune.dev/api/v1/github/webhook |
| Webhook secret | Generate a random secret and store it as GITHUB_WEBHOOK_SECRET |
Adjust the hostnames to match your actual deployment domains.
Repository permissions
Use the current minimum permission set:
| Permission | Access |
|---|
| Contents | Read-only |
| Metadata | Read-only |
Optional write-back permissions
If you want SelfTune to post publish results back to GitHub, also grant:
| Permission | Access | Why |
|---|
| Checks | Read & write | Create and update GitHub check-runs for publish attempts |
| Commit statuses | Read & write | Post commit status fallback for the same publish attempts |
Subscribe to events
Enable these webhook events:
| Event | Why SelfTune needs it |
|---|
push | Publish commit-based versions from the configured default branch |
create | Publish release versions from matching Git tags |
installation | Track install, suspend, unsuspend, and delete lifecycle |
installation_repositories | Detect repo access changes on an installation |
Keep the app unlisted until you have verified the full flow in a staging or
internal environment.
API service
Set these variables for the API process:
GITHUB_APP_ID=1234567
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----"
GITHUB_WEBHOOK_SECRET="replace-with-random-secret"
These are read in packages/api/src/config.ts.
Dashboard
Set the GitHub install URL for the dashboard process:
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL="https://github.com/apps/YOUR-APP-SLUG/installations/new"
This enables the one-click install button in the dashboard GitHub settings page at src/app/settings/github/page.tsx.
Step 3: Apply the database migration
Apply the GitHub registry foundation migration before using the dashboard flow:
That migration creates:
github_installations
github_connections
github_publish_attempts
- registry visibility and GitHub source metadata fields
- org-level and connection-level write-back settings
Step 4: Restart the services
After setting env vars and applying the migration, restart:
- the API service
- the dashboard service
The API must come back with the GitHub credentials loaded, or repo listing and webhook handling will fail.
Step 5: Install and bind the GitHub App
Open the dashboard GitHub settings page
Go to /settings/github in the dashboard.
Install the GitHub App
Click Connect GitHub App, or go directly to the install URL you set in
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL.
Choose the GitHub account and repositories
Install the app on the GitHub user or organization that owns the skill
repository. Limit the install to the repos you want SelfTune to read.
Return to SelfTune
GitHub redirects back to /settings/github?installation_id=....
Verify the installation was bound
The dashboard should show the installation under the bound-installations
list and display the connected state.
Step 6: Connect a repository to a registry entry
From the same GitHub settings page:
- Select the bound installation
- Pick the target registry entry
- Pick the GitHub repo
- Confirm
default_branch
- Confirm or choose
skill_path
- Set the tag pattern, usually
v*
- Save the connection
If the repo is a monorepo, the dashboard should discover SKILL.md paths and
let you choose the correct subpath.
Step 7: Verify publishing
Run the verification in this order.
Manual sync
Use the dashboard Sync now control first.
Expected result:
- a GitHub-backed version is created in the registry
- the version source is
github
- the version
source_ref is the commit SHA
Default-branch push
Push a commit to the connected default branch.
Expected result:
- the webhook reaches
/api/v1/github/webhook
- SelfTune packages the skill path
- a new prerelease-style version is published, such as
0.0.0-github.abcdef1
Tag publish
Push a matching tag such as v1.2.0.
Expected result:
- the webhook create event is accepted
- the connection’s
tag_pattern matches
- a registry version is published using the tag-derived version number
Optional write-back verification
If you enabled the optional GitHub permissions:
- In the dashboard, set org write-back mode to
checks
- Enable write-back on one repo connection
- Run
Sync now
Expected result:
- the commit receives a
selftune/publish/... status context
- the commit or pull request shows a
Selftune publish check-run
- success, skip, and failure outcomes match the registry publish result
Smoke-test checklist
Use this after initial setup:
GET /api/v1/github/installations returns the bound installation
GET /api/v1/github/repos?installation_id=... returns the expected repos
- the dashboard can discover
SKILL.md paths for the repo
- manual sync publishes successfully
- a push to the default branch auto-publishes
- a matching tag auto-publishes
- disconnecting the connection leaves already-published registry versions intact
- deleting the GitHub installation removes the bound installation row
- optional write-back posts a commit status and check-run when enabled
Troubleshooting
The dashboard says GitHub install is unavailable
Check:
NEXT_PUBLIC_GITHUB_APP_INSTALL_URL is set on the dashboard
- the dashboard was restarted after setting it
Repo listing fails
Check:
GITHUB_APP_ID
GITHUB_APP_PRIVATE_KEY
- the GitHub App is installed on the selected account
- the selected repo is included in the installation scope
Webhook publishing does not fire
Check:
- the GitHub App webhook URL points to
/api/v1/github/webhook
GITHUB_WEBHOOK_SECRET matches the GitHub App webhook secret
- the
push and create events are subscribed
- the repo connection exists and
auto_publish is enabled
Manual sync says No SKILL.md found
Check:
skill_path points at the actual skill root
- the repo contains
SKILL.md at that path
- monorepo discovery returned the expected path
Current limitation: no PR or branch mutation write-back
SelfTune now supports Tier A write-back: commit statuses and check-runs.
It still does not support:
- remediation pull request creation
- direct branch or tag mutation
- release creation
Keep those as a separate future permission tier. That lets teams adopt
repo-to-registry publishing and publish-result visibility without granting
source mutation access to the GitHub App.
If you want to plan the next tier, use this permission model:
| Capability | Suggested permission change | Why |
|---|
| Check-runs and commit statuses | Checks: Read & write, Commit statuses: Read & write | Show publish and validation results on commits and PRs without mutating repo contents |
| Remediation pull requests | Pull requests: Read & write, Contents: Read & write | Let SelfTune open fix PRs for cases like missing metadata or packaging issues |
| Direct branch/tag mutation | Not recommended for v1 | Highest-risk mode; avoid until checks and PR flows are proven |