Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/paramveer-cyber/Deployaar/llms.txt

Use this file to discover all available pages before exploring further.

Deployaar integrates with GitHub through a GitHub App — not a personal access token or a classic OAuth token. A GitHub App grants fine-grained, organization-level repository access, generates short-lived installation tokens instead of storing long-lived credentials, and can be installed to specific repositories rather than an entire account. This is what allows Deployaar to clone private repositories, push branches, and open pull requests on your behalf without ever storing a permanent GitHub credential.
Deployaar uses two distinct sets of GitHub credentials that serve different purposes and must not be confused:
  • GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET — these belong to a GitHub OAuth App and are used exclusively by better-auth for the “Sign in with GitHub” social login flow. They grant no repository access.
  • GITHUB_APP_ID / GITHUB_PRIVATE_KEY — these belong to the GitHub App and are used by packages/services/github for all repository operations: cloning, pushing, opening PRs, and reading diffs. They grant no login capability.
Setting the wrong credentials in the wrong variable causes authentication failures that are difficult to diagnose. Keep them separate.

Setting Up the GitHub App

1

Create a GitHub App in your organization

Go to your GitHub organization’s settings → Developer settingsGitHub AppsNew GitHub App. Give it a name (e.g., “Deployaar”) and a homepage URL.
2

Configure required permissions

Set the following repository permissions:
PermissionLevel
ContentsRead and write
Pull requestsRead and write
MetadataRead (required by GitHub, always enabled)
Deployaar does not require any organization or account permissions.
3

Set the webhook URL

Enter your API domain’s webhook endpoint:
https://your-api-domain.com/api/github/webhook
Enable the following webhook events: Pull requests, Issues.
4

Generate and download the private key

Scroll to the bottom of the App settings page and click Generate a private key. Download the .pem file. This is the only time GitHub gives you the key — store it securely.
5

Set environment variables

Add the following to your API server’s environment:
GITHUB_APP_ID=<your app's numeric ID>
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
GITHUB_WEBHOOK_SECRET=<a random secret you set in the App's webhook config>
The GITHUB_APP_PRIVATE_KEY value can contain literal \n escape sequences — the getGithubApp() initializer calls .replace(/\\n/g, "\n") to convert them to real newlines before passing the key to Octokit.

Installing the App

Creating the GitHub App is a one-time setup step. After creation, each user or organization that wants to use Deployaar must install the App to grant it access to their repositories. Users install the App from the Deployaar settings page at /dashboard/settings/github. The installation flow redirects to GitHub, where the user selects which repositories to grant access to. On completion, GitHub stores the installation record and Deployaar records the installationId against the user’s account. An installationId is required for every repository operation. Deployaar resolves it through getInstallationOctokit(userId), which fetches the stored installation from the database and calls app.getInstallationOctokit(installation.installationId).

Linking a Repository to a Project

Every Deployaar project is linked to exactly one GitHub repository. The linked repository is:
  • The one the coding agent shallow-clones into the E2B sandbox
  • The one the agent pushes branches to and opens PRs against
  • The one whose webhook events are routed to the corresponding feature requests
A project without a linked repository cannot have feature requests created on it:
const linkedRepository = await getRepoByProject(projectId);
if (!linkedRepository) {
  throw ApiError.badRequest(
    "A repository must be linked to this project before creating feature requests",
  );
}
To link a repository, go to the project’s settings page and select from the list of repositories your GitHub App installation has access to.

Webhook Events

Deployaar handles two categories of GitHub webhook events. Every incoming webhook is first verified for authenticity before any logic runs.
Every webhook payload is verified using HMAC-SHA256 with GITHUB_WEBHOOK_SECRET:
const isSignatureValid = await app.webhooks.verify(rawBody, signature);
if (!isSignatureValid) {
  throw new Error("Invalid signature");
}
Webhooks with invalid signatures are rejected immediately with no processing. Duplicate deliveries (identified by the X-GitHub-Delivery ID) are also deduplicated — Deployaar records each delivery ID in github_webhook_deliveries and ignores redeliveries.
pull_request events — routed when the action is opened, synchronize, or reopened. The webhook handler fires the github/pull-request.received Inngest event for all matching repos. Inside the onPullRequestReceived Inngest function, the head.ref branch name is checked against the pattern deployaar_([0-9a-f-]{36}). If it matches, the feature request ID is extracted and AI review runs. PRs from branches that don’t match the pattern are silently skipped at the Inngest function level. issues events — routed when the action is opened or edited. A new feature request is created from the issue title and body with source: "feature_request_issue". Duplicate issues (same repoId + issueNumber) are returned as-is without creating a duplicate record. Webhook events for repositories not connected to any Deployaar project are silently ignored — no error, no processing.

GitHub API Operations

Deployaar uses Octokit (via packages/services/github) for the following operations. All calls use an installation-scoped Octokit instance, never a user token.
OperationAPI Endpoint
List repositories for an installationGET /installation/repositories
Get a single repositoryGET /repos/{owner}/{repo}
List branchesGET /repos/{owner}/{repo}/branches
List commitsGET /repos/{owner}/{repo}/commits
List issuesGET /repos/{owner}/{repo}/issues
List pull requestsGET /repos/{owner}/{repo}/pulls
Get a pull requestGET /repos/{owner}/{repo}/pulls/{pull_number}
Get PR files (diff)GET /repos/{owner}/{repo}/pulls/{pull_number}/files
Get PR commitsGET /repos/{owner}/{repo}/pulls/{pull_number}/commits
Create a pull requestPOST /repos/{owner}/{repo}/pulls
Merge a pull requestPUT /repos/{owner}/{repo}/pulls/{pull_number}/merge
The create and merge operations are the two write operations. Creates are performed by the coding agent at the end of a successful run. Merges are performed when a human owner or admin calls the ship action after a review passes, using squash merge with a commit title of feat: {featureRequest.title} (#prNumber).

Installation Tokens

Deployaar never stores a GitHub access token in the database. For each clone and push operation the coding agent needs to perform, a short-lived installation token is generated on demand:
async function generateInstallationToken(installationId: number): Promise<string> {
  const app = await getGithubApp();
  const octokit = await app.getInstallationOctokit(installationId);
  const { data } = await octokit.request(
    "POST /app/installations/{installation_id}/access_tokens",
    { installation_id: installationId },
  );
  return data.token;
}
These tokens are used inline in git clone and git push URLs and are never written to disk or stored in any database table. GitHub installation tokens expire after one hour, which is well within the time window of a single agent run.
For GitHub OAuth login setup (the “Sign in with GitHub” button), see Authentication. The OAuth App credentials (GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET) are configured separately from the GitHub App credentials used here.

Build docs developers (and LLMs) love