Your app works with the code, Change Requests and checks of every repository it's installed on.

One app can do all six.

Host your users' code

Clone and push the repositories an owner gave your app.

Permissions
repo:readcontents:write
Events
pushcreatedelete
Get a token. It lasts an hour.$curl -X POST -H "Authorization: Bearer $APP_JWT" https://api.upstream.codes/api/v3/app/installations/41/access_tokensClone with it.$git clone https://x-access-token:$TOKEN@upstream.codes/acme/shop.git

The CLI creates the app and writes a starter that runs. Webhooks reach your machine without a tunnel.

List it yourself
Public apps go in the app directory. No review queue.
Keep your private key
Upload a public key or point to a JWKS URL. Ed25519, P-256 and RSA work.
Check installs offline
Install receipts and webhooks are signed. Verify them with our public keys.
$upstream app create previewsCreates the app and an Octokit starter.$cd previews && npm install$npm run devRuns it and forwards its webhooks here.$upstream app installOpens the install page.

Everything your app hears and says, in the order it happens.

  1. 1

    An owner installs

    They pick repositories and approve access. Then they land back on your site with a signed receipt.

  2. 2

    You get a token

    Sign a JWT with your app's key and trade it for a token that lasts an hour.

  3. 3

    Work comes to you

    Pushes, Change Requests and check suites arrive at your webhook, signed.

  4. 4

    You answer as your bot

    Report checks, review and push as previews-bot.

GitHub App libraries work against Upstream. Change the base URL and keep the rest.

  • The same app JWT

    Sign with your app's RS256 key and trade it for installation tokens.
  • The same webhooks

    Deliveries carry X-GitHub-Event and X-Hub-Signature-256. Webhook libraries verify them unchanged.
  • The same REST API

    Pulls, reviews, check runs and Actions at /api/v3. See what differs.
import { App, Octokit } from "octokit";

const app = new App({
  appId,
  privateKey,
  webhooks: { secret },
  Octokit: Octokit.defaults({
    baseUrl: "https://api.upstream.codes/api/v3",
  }),
});

app.webhooks.on("check_suite.requested", ({ octokit, payload }) =>
  octokit.rest.checks.create({
    owner: payload.repository.owner.login,
    repo: payload.repository.name,
    head_sha: payload.check_suite.head_sha,
    name: "build",
  }),
);

People install your app because they can see exactly what it reaches.

Owners pick the repositories
All of them, including ones created later, or a list they can change at any time.
Tokens last an hour
Installation tokens reach only the installation's repositories, with the permissions the owner approved.
New access waits for approval
Removing a permission takes effect right away. Adding one asks every owner again, and installations keep their current access until they approve.
Bots stay out of settings
A bot can't change repository settings, delete or transfer repositories, manage webhooks or assign people.

Anyone can create an app today. If you're building a product on Upstream, tell us about it and we'll help you plan the integration.

Where would you plug in?

Or email support@coline.app

Apps are free to build and install on every plan.