Skip to main content
This guide walks you through creating and configuring a GitHub App for Konduktor. The GitHub App enables:
  • Authenticated repository cloning — agents clone private repos using short-lived installation tokens
  • PR lifecycle automation — webhooks automatically move tasks to “done” when PRs are merged and detect merge conflicts

Prerequisites

  • A running Konduktor server (konduktor-server start)
  • A GitHub account with permission to create GitHub Apps
  • Your Konduktor server accessible from the internet (for webhook delivery)
Local development? If your server isn’t publicly accessible, use a tunnel service like zrok, ngrok, or Cloudflare Tunnel to expose it.

Step 1: Create the GitHub App

  1. Go to GitHub Settings > Developer settings > GitHub Apps > New GitHub App
  2. Fill in the basic fields:
    FieldValue
    App nameSomething unique, e.g. konduktor-myteam
    Homepage URLYour Konduktor server URL, or https://github.com/yakkomajuri/konduktor-oss
  3. Configure the Webhook section:
    FieldValue
    ActiveChecked
    Webhook URLhttps://<your-konduktor-host>/api/webhooks/github
    Webhook secretA random secret (see below)
    Generate a webhook secret:
    openssl rand -hex 32
    
    Save this value — you’ll need it when configuring the Konduktor server.
  4. Set Permissions (under “Permissions & events”):
    CategoryPermissionAccess
    RepositoryContentsRead-only
    RepositoryPull requestsRead & write
    RepositoryMetadataRead-only (auto-selected)
    • Contents (read) — allows cloning repositories with installation tokens
    • Pull requests (read & write) — allows reading PR status for merge conflict detection and task automation
    • Metadata (read) — required by GitHub for all apps, auto-selected
  5. Under Subscribe to events, check:
    • Pull request
    This triggers webhooks when PRs are opened, closed, merged, or updated — enabling automatic task lifecycle management.
  6. Under Where can this GitHub App be installed?, select:
    • Only on this account (recommended for self-hosted setups)
    • Or Any account if you need cross-organization support
  7. Click Create GitHub App.

Step 2: Note your App ID

After creation, you’ll land on the app’s settings page. Note the App ID displayed near the top — you’ll need it during configuration. The App ID is a numeric value (e.g. 123456).

Step 3: Generate a private key

Still on the app settings page:
  1. Scroll down to Private keys
  2. Click Generate a private key
  3. A .pem file will download automatically — save it somewhere accessible to your server
This private key authenticates your server as the GitHub App. Keep it secure and never commit it to version control.

Step 4: Install the app on your repositories

  1. In the app settings sidebar, click Install App
  2. Select the account (user or organization) where your repositories live
  3. Choose repository access:
    • All repositories — the app works with every repo in the account
    • Only select repositories — pick specific repos (recommended)
  4. Click Install
After installation, GitHub assigns an Installation ID — Konduktor discovers this automatically during configuration.

Step 5: Configure Konduktor

Run the interactive configuration command:
uv run konduktor-server configure-github-app
You’ll be prompted for three values:
=== GitHub App Setup ===
  App ID: <your-app-id>
  Webhook secret: <your-webhook-secret>
  Path to PEM file: /path/to/your-app.private-key.pem
The command will:
  1. Copy the PEM file to ~/.konduktor/github-app.pem (with 0600 permissions)
  2. Auto-discover the installation ID by querying the GitHub API
  3. Save the configuration to ~/.konduktor/github-app.json (with 0600 permissions)
Expected output:
  Discovering installation ID...
  Found installation ID: 12345678
GitHub App configured.

Configuration files

After setup, two files are created in ~/.konduktor/:
FileContents
github-app.jsonapp_id, installation_id, webhook_secret
github-app.pemRSA private key for JWT authentication
Both files are created with 0600 permissions (owner read/write only).

Custom data directory

If you use a custom data directory, set the KONDUKTOR_DIR environment variable before running the configuration:
export KONDUKTOR_DIR=/opt/konduktor/data
uv run konduktor-server configure-github-app

Step 6: Restart the server

Restart Konduktor so it picks up the new GitHub App configuration:
uv run konduktor-server start
The webhook endpoint POST /api/webhooks/github is now active.

Step 7: Verify the setup

Test webhook delivery

  1. Go to your GitHub App settings page: https://github.com/settings/apps/<your-app-name>
  2. Click Advanced in the sidebar
  3. Check Recent Deliveries — you should see a ping event from when the app was installed
  4. Click the delivery and verify it shows a 200 response

Test with a pull request

  1. Create a test PR on a repository where the app is installed
  2. Include a kid tag in the PR title — e.g. Test PR [kid: #abcd1234] (where abcd1234 matches the first 8+ characters of a task ID)
  3. Check Konduktor’s server logs for processing output:
    INFO: Task abcd1234 has_merge_conflict=False
    
  4. Merge the PR — the linked task should automatically move to the “done” column

Verify authenticated cloning

# Clone a private repo through Konduktor to verify token authentication works
uv run python -c "
import asyncio
from konduktor.github import get_installation_token
token = get_installation_token()
print('Token obtained successfully' if token else 'No token - check config')
"

How it works

Webhook flow

PR event on GitHub
       |
GitHub sends POST to https://<your-host>/api/webhooks/github
       |
Konduktor verifies HMAC-SHA256 signature using the webhook secret
       |
Konduktor extracts the kid tag from the PR title — e.g. [kid: #abcd1234]
       |
Matches the tag to a task in the database
       |
Takes action based on the event:
  - PR merged  →  task moves to "done"
  - PR opened/updated  →  checks mergeable status for conflicts

Authentication flow

Konduktor creates a JWT signed with the App's private key
       |
Exchanges the JWT for a short-lived installation access token (via GitHub API)
       |
Uses the token for:
  - Authenticated git clone
  - GitHub API calls
       |
Tokens are cached and auto-refreshed when <5 minutes from expiry

Kid tags

Konduktor links PRs to tasks using kid tags in PR titles. The format is:
Your PR title here [kid: #<task-id-prefix>]
For example: Fix login timeout [kid: #4d9d444d] The tag prefix must match the first 8+ hex characters of a task ID. When agents create PRs through Konduktor, kid tags are added automatically.

Troubleshooting

Webhook returns 503

Cause: GitHub App is not configured on the Konduktor server. Fix: Run uv run konduktor-server configure-github-app and restart the server.

Webhook returns 401

Cause: Webhook signature verification failed — the webhook secret doesn’t match. Fix: Ensure the webhook secret in your GitHub App settings matches the one stored in ~/.konduktor/github-app.json. Re-run configure-github-app if needed.

”No installations found” during configuration

Cause: The GitHub App hasn’t been installed on any account yet. Fix: Go to your app’s settings page, click Install App, and install it on your account/organization (Step 4).

”Multiple installations found”

Cause: The app is installed on more than one account. Fix: The error message lists all installations with their IDs. Currently, Konduktor auto-discovers the installation ID when there’s only one. If you have multiple installations, you may need to re-install the app on only the target account, or manually edit ~/.konduktor/github-app.json to set the correct installation_id.

Webhook events are not reaching the server

  1. Check your server is accessible from the internet at the webhook URL
  2. In your GitHub App settings, go to Advanced > Recent Deliveries to see if GitHub is sending events
  3. If deliveries show connection errors, verify your tunnel or DNS setup
  4. Ensure your firewall allows inbound HTTPS traffic on the server port

PR merged but task didn’t move to “done”

  1. Verify the PR title contains a valid kid tag: [kid: #<prefix>]
  2. Check that the task ID prefix matches an existing task
  3. Confirm the task is in the pr_submitted column (only tasks in pr_submitted move to done on merge)
  4. Check server logs for processing details

Updating the GitHub App

Changing the webhook URL

If your server address changes (e.g. new domain, new tunnel URL):
  1. Go to your GitHub App settings
  2. Update the Webhook URL field
  3. Click Save changes
No server-side changes are needed.

Rotating the webhook secret

  1. Generate a new secret: openssl rand -hex 32
  2. Update the secret in your GitHub App settings
  3. Re-run uv run konduktor-server configure-github-app with the new secret
  4. Restart the server

Regenerating the private key

  1. Go to your GitHub App settings > Private keys
  2. Click Generate a private key (a new .pem file downloads)
  3. Optionally revoke the old key
  4. Re-run uv run konduktor-server configure-github-app with the path to the new PEM file
  5. Restart the server