Skip to main content

GitHub App setup

Bloom uses a GitHub App to create and manage repositories. One App (owned by the hidden-claw org) serves both cases:

  • Bloom-hosted (default): the App is installed on hidden-claw; Bloom creates each project's repo there.
  • Client-owned (opt-in): the client installs the same App on their org; Bloom creates the repo there, so the client owns the code and can revoke access at any time.

Bloom never stores a long-lived credential for any account - it mints a short-lived installation token per action from the App's private key.

One-time registration (operator)

  1. Create the App at https://github.com/organizations/hidden-claw/settings/apps/new:

    • Name: bloom-po (the slug becomes part of the install URL).
    • Homepage URL: your Bloom URL.
    • Setup URL: https://<your-bloom-host>/webhooks/github/setup and tick "Redirect on update". Bloom links the new installation to the project here.
    • Webhook URL: https://<your-bloom-host>/webhooks/github with a secret (reused as BLOOM_GITHUB_WEBHOOK_SECRET). Subscribe to Pull request and Issues events (Issues events drive the blocked-work and milestone-completion notifications, FR-10).
  2. Permissions (Repository) - what the running flows actually use:

    • Administration: Read & write (create repositories)
    • Issues: Read & write (tickets, labels, milestones)
    • Pull requests: Read & write (the engine opens PRs; Bloom reviews and merges them)
    • Contents: Read & write (branch pushes, PRD.md/README commits)
    • Variables: Read & write (M19-4: publish the non-secret INFISICAL_* deploy coordinates; without it, delivery provisioning 403s - #293)
    • Metadata: Read (default)

    Changing permissions on an existing App requires the org to accept the updated permissions on its installation (GitHub prompts the installation admin).

  3. Generate a private key (.pem) and download it. Store it as a secret - never commit it.

  4. Install the App on hidden-claw and note the installation id (visible in the installation URL: .../installations/<id>).

Configuration (env)

Set these (see .env.example):

BLOOM_GITHUB_APP_ID=<app id>
BLOOM_GITHUB_APP_SLUG=bloom-po
BLOOM_GITHUB_APP_PRIVATE_KEY_PATH=/run/secrets/bloom-app.pem # or BLOOM_GITHUB_APP_PRIVATE_KEY
BLOOM_GITHUB_DEFAULT_ORG=hidden-claw
BLOOM_GITHUB_DEFAULT_INSTALLATION_ID=<hidden-claw installation id>
BLOOM_GITHUB_WEBHOOK_SECRET=<same secret as the App webhook>
BLOOM_PUBLIC_BASE_URL=https://<your-bloom-host>

When BLOOM_GITHUB_APP_ID and a private key are present, Settings.github_app_configured is true and Bloom wires up GitHub. Without them, GitHub steps are skipped and the rest of the app runs normally.

Client-owned flow (what the founder does)

  1. In Telegram the client sends "use my own org" (or /useownorg).
  2. Bloom replies with a one-tap install link (https://github.com/apps/bloom-po/installations/new?state=<thread>).
  3. The client installs the App on their org and approves the permissions.
  4. GitHub redirects to …/webhooks/github/setup; Bloom records the installation as the project's repo target and confirms in Telegram.
  5. On plan approval, Bloom creates the repo in the client's org.

Choose client-owned before approving the plan - once the repo is created in hidden-claw, moving it to the client's org requires a GitHub repository transfer.

Adopting an existing repository

The same App powers repository adoption (M44): instead of Bloom creating the repo at plan approval, a project can bind a pre-existing repository as its target via the optional repo: "owner/name" field on the create call. Install the App on the account that owns the repository and grant it access to that repo; the bind resolves the covering installation and read-preflights it before the project is created. Personal accounts work for adoption - the organizations-only rule below applies to repository creation.

Notes

  • Organizations only. Repo creation targets an org (POST /orgs/{org}/repos); installing on a personal account is rejected with guidance to use an org.
  • Rotation. To rotate the key, generate a new private key in the App settings and update the secret; installation tokens are short-lived and refresh automatically.