Skip to content

Onboard a Project to TellBoB

Get a task done. Give a project a TellBoB intake front-door — invited reporters get a shared link that turns freeform reports into approved, BoB-convention GitHub issues. Onboarding is a config change plus a deploy: no code changes, ever (#1099). (Back to docs home.)

TellBoB is the multi-tenant intake Worker at apps/intake/ (see its README for architecture). Each tenant is one entry in apps/intake/config/projects.json.

Live deployment (#1364): https://tellbob-intake.paul-bb4.workers.dev, serving tenants bigbrain and oos. Committed config stores token SHA-256 digests only; plaintext reporter links live with the operator at ~/.claude/secrets/tellbob-reporter-links.md (see the README's "Live deployment" section for bindings and secrets).

Onboard

1. Add the config entry

In apps/intake/config/projects.json, add one entry under projects — the key is the URL slug reporters will visit:

json
"my-project": {
  "name": "My Project",
  "repo": "owner/my-project",
  "tokens": [
    { "label": "alice", "token_sha256": "<sha-256 hex of `openssl rand -hex 16`>" }
  ],
  "areas": ["frontend", "api"],
  "context": "One paragraph grounding the drafting model in what this project is."
}

Real tenants commit only the SHA-256 digest of each reporter secret (token_sha256); the plaintext value goes in the reporter's link and never in the repo. Issue each reporter their token per the token lifecycle runbook. R2 attachment prefixes (pending/my-project/…, projects/my-project/…) derive from the slug automatically — nothing to provision.

2. Create the project's Access application (#1511)

Each onboarded project is gated by its own Cloudflare Access application, scoped to tellbob.iwpi.com/<slug> — identity (email OTP) in front of the token layer; see the README's "Access gating" section for the layering. Declare it, then converge:

  1. In apps/intake/config/access.json, add the slug under projects with the emails allowed to reach the form:

    json
    "my-project": {
      "allowed_emails": ["reporter@example.com"]
    }
  2. Apply (idempotent; needs an operator-local CLOUDFLARE_API_TOKEN with Access: Apps and Policies — Edit on the account):

    bash
    cd apps/intake && npm run access:apply

Reporters must be on both lists to file: their email on the Access allow-list (gets them to the form), and a named token row (attributes their reports). Adding either later is a config edit + apply/deploy.

3. Preconditions — GitHub App installation and labels

Two preconditions must hold before the tenant goes live:

  • GitHub App installed on the target repo. Issue filing uses a repo-scoped installation token from the TellBoB GitHub App — if the App isn't installed on owner/my-project, filing 502s. Install it (App settings → Install App → add the repo); creating the App in the first place is the GitHub App runbook.
  • Standard BoB label set on the target repo. Filed issues carry type/priority/area labels plus approved; the repo must have the standard set (scripts/bootstrap-labels.sh ensure --repo owner/my-project if not).

Run the onboarding check — it verifies the config entry, the label set, and the Access gating entry (exit 4 if missing), and states the App precondition:

bash
apps/intake/scripts/onboard-check.sh my-project

Expected output: onboarding preconditions pass for 'my-project'. A label gap exits 3 and prints the exact bootstrap-labels.sh ensure remediation.

4. Deploy and verify

bash
cd apps/intake && npm test && npm run deploy

Verify end to end — the App-installation verification step: run the filing smoke test from the GitHub App runbook's Verify section against the new slug. A 201 with an issue URL (labels + approved + the reporter footer on the created issue) proves the whole path; a 502 with nothing created means the App isn't installed on that repo.

Then send reporters their links: https://<worker-host>/my-project?t=<token>.

Offboard

Offboarding reverses the same declarative unit:

  1. Revoke every token for the project (set "revoked": true — keep the rows; they are the attribution history for issues already filed). Deploy. This alone kills access while preserving everything else.
  2. Remove the config entry once the tenant is confirmed dead (a grace period with revoked-but-present entries costs nothing). Deploy. The slug now 404s before token handling.
  3. R2 prefix retention stance: attachments under projects/my-project/issues/… are retained — they are linked from filed GitHub issues, which outlive the tenant; deleting them would break issue history. (Served links stop resolving once the config entry is gone — retention is for the record, not for serving.) Anything still under pending/my-project/… needs no action: the 7-day lifecycle rule expires it. Only scrub projects/<slug>/ explicitly (wrangler r2 object delete) if the offboarding is a data-removal request, and note it on the issues that linked the files.