📖 Cookbook: Build a multi-user GitHub PR summarizer agent
Provision these keys before clicking the button above.
**1. LITELLM_API_KEY (required), LITELLM_BASE_URL (optional)
The app uses the standard OpenAI SDK. Set LITELLM_API_KEY to your OpenAI API key and leave LITELLM_BASE_URL unset to call OpenAI directly — no LiteLLM server needed. Set LITELLM_BASE_URL only if you're routing through a proxy.
The default model is gpt-5.4-mini, which works with an OpenAI key and no proxy. To use Claude, set LITELLM_BASE_URL to an Anthropic-compatible proxy and set LITELLM_MODEL accordingly.
2. Scalekit credentials → SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET
- Sign up or log in at app.scalekit.com
- Select AgentKit
- Navigate to settings in the left sidebar
- Copy the Environment URL and Client ID from the environment settings
- Click
Generate new secretin the bottom right - Copy the secret you just created
- Go to User verification settings
- Set it to Custom user verifier
3. Scalekit GitHub connector → GITHUB_CONNECTION_NAME
- In the Scalekit Dashboard, navigate to Connectors in the left sidebar
- Click
Create Connectionin the top right - Search for GitHub and click Create
- Copy the generated connection name — this is your
GITHUB_CONNECTION_NAME - Enter the
SCALEKIT_CLIENT_IDandSCALEKIT_CLIENT_SECRETfrom the previous step - Click Save
4. Deploy
When Render prompts for environment variables, fill in the values from steps 1–4. Leave PUBLIC_BASE_URL blank for now. SESSION_SECRET and PORT are set automatically.
5. Pin the OAuth callback → PUBLIC_BASE_URL
After the first deploy, copy your auto-assigned service URL (e.g. https://your-service.onrender.com) from the Render Dashboard. Set PUBLIC_BASE_URL to that URL and trigger a redeploy to pin the OAuth callback origin.
This sample shows how to build a GitHub PR summarizer where each browser session connects its own GitHub account once, then uses that connected token for later tool calls. The server never asks the browser for a userId.
The app finds the five most-discussed open pull requests in a repository, fetches each PR's diff and comment thread through Scalekit's GitHub connector, then calls an LLM through any OpenAI-compatible API to produce a plain-language summary.
The server mints an opaque identifier on the server side and stores it in its own session record. The browser only carries a signed, HTTP-only session cookie.
That design matters because the connected GitHub token is stored in Scalekit under the identifier you provide. If you let the browser choose that identifier, one user can point requests at another user's stored token. This sample avoids that cross-user impersonation bug by binding the identifier to the server-side session and completing the OAuth flow with Scalekit's user verification callback.
See User verification for connected accounts for the full Scalekit flow.
- A browser visits
/and receives a signed, HTTP-only session cookie. - The server mints an opaque identifier such as
usr_...for that session. POST /api/authcreates a GitHub auth link with a one-timestateand auserVerifyUrl.- After GitHub OAuth completes, Scalekit redirects the browser to
/user/verify. - The server validates
state, callsverifyConnectedAccountUser, marks the session connected, and redirects back to/. POST /api/summarizereads the identifier from the session and runs GitHub tool calls on behalf of that connected account.
The app serves a browser UI at http://localhost:3000 in development or at your Render service URL in production.
The UI has two steps:
- Connect GitHub. Click Connect GitHub and complete the OAuth flow in the same browser session.
- Summarize pull requests. Paste a GitHub repository URL or enter
owner/repo, then generate summaries.
When the callback succeeds, the page shows a GitHub connected banner. There is no user ID field anywhere in the UI.
Starts the GitHub connection flow for the current browser session.
- No request body
- Browser-driven flow
- Returns
{ "authLink": "https://..." }
This endpoint is only useful from a browser session because the callback relies on the signed session cookie.
Completes the connected-account verification flow after Scalekit redirects back with auth_request_id and state.
- Validates the one-time
state - Calls
verifyConnectedAccountUser - Marks the session as connected
- Redirects back to
/
Summarizes the top open PRs for a repository using the GitHub account connected to the current session.
curl -X POST https://your-service.onrender.com/api/summarize \
-H "Content-Type: application/json" \
--cookie "sid=YOUR_SIGNED_SESSION_COOKIE" \
-d '{"repository":"https://github.com/octocat/Hello-World"}'| Field | Description |
|---|---|
repository |
GitHub repository URL or owner/repo value |
owner |
Optional backward-compatible owner field |
repo |
Optional backward-compatible repo field |
If the session has not connected GitHub yet, the server returns 401.
- Open app.scalekit.com and go to Agent Auth > Connectors
- Add a GitHub connector
- Finish the connector setup
- Copy the generated connection name into
GITHUB_CONNECTION_NAME
This sample uses the secure connected-account verification flow from Scalekit's docs.
- In the Scalekit Dashboard, go to AgentKit > Settings > User verification and set it to Custom user verification
- Set
PUBLIC_BASE_URLif you want to pin the callback origin explicitly - If
PUBLIC_BASE_URLis unset, the app falls back to the incoming request origin - The app sends
${PUBLIC_BASE_URL}/user/verifyasuserVerifyUrlwhen it creates the GitHub auth link when that variable is set
cp .env.example .env
npm installFill in .env with your Scalekit and LLM settings.
Important variables:
SESSION_SECRET: generate withopenssl rand -hex 32PUBLIC_BASE_URL: optional override for the callback origin; set it tohttp://localhost:3000locally or your public Render URL in production if you want to pin the callback URL explicitlyGITHUB_CONNECTION_NAME: copy from the Scalekit dashboard
npm run devOpen http://localhost:3000, click Connect GitHub, finish OAuth, then paste a GitHub repository URL or enter owner/repo.
After the callback succeeds, the page shows a GitHub connected banner and the Step 1 button changes to Reconnect GitHub.
Public repositories work with any connected GitHub account. Private repositories only work if the connected account has access.
Browser
│
▼ GET /
Express server
│ issues signed HTTP-only session cookie
▼ POST /api/auth
Scalekit connected account + auth link
│
▼ GET /user/verify?auth_request_id=...&state=...
Express server validates state and calls verifyConnectedAccountUser
│
▼ POST /api/summarize { repository }
Render tasks + Scalekit GitHub connector + LLM
| Task | Purpose |
|---|---|
setupGitHubAuth |
Creates the GitHub authorization link for the current server-side identifier |
summarizePRs |
Orchestrates the PR summary flow for the current session |
fetchOpenPRs |
Lists open PRs through Scalekit's GitHub connector |
fetchPRDetails |
Fetches PR diffs and comments through the connector |
generateSummary |
Calls the LLM to produce plain-language summaries |
- The sample stores sessions in memory. Use Redis or a database-backed shared session store in production.
- The signed cookie detects tampering. The actual identifier stays server-side in the session store.
- The
statevalue is single-use and expires after 10 minutes. - The app requires the connected GitHub token to have access to the target repository.