Appearance
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:
In
apps/intake/config/access.json, add the slug underprojectswith the emails allowed to reach the form:json"my-project": { "allowed_emails": ["reporter@example.com"] }Apply (idempotent; needs an operator-local
CLOUDFLARE_API_TOKENwith Access: Apps and Policies — Edit on the account):bashcd 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-projectif 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-projectExpected 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 deployVerify 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:
- 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. - 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.
- 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 underpending/my-project/…needs no action: the 7-day lifecycle rule expires it. Only scrubprojects/<slug>/explicitly (wrangler r2 object delete) if the offboarding is a data-removal request, and note it on the issues that linked the files.
Related
- Token lifecycle runbook — issue / rotate / revoke reporter tokens
- GitHub App runbook — create/install the App, secrets, rotation
apps/intake/README.md— config shape, architecture, filing contract