--- title: "Operating Jinx" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Operating Jinx} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r} #| include: false knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` This page is for the people who maintain Jinx — registering the GitHub App, deploying the Cloudflare Worker, wiring in new commands. If you just want to use Jinx, [Getting started](jinx.html) is the page you want. For the architecture map (what runs where, who triggers it), see [How Jinx is built](architecture.html). This page is the *operational* counterpart: what you do to stand it up, change it, and keep it running. ## Register the GitHub App Jinx posts as `jinx[bot]` because it authenticates as a registered GitHub App, not a maintainer's PAT. Set up in *Settings → Developer settings → GitHub Apps → New* on the org: - Name: `jinx`. - Permissions: - Repository: Issues (R/W), Pull Requests (R/W), Contents (Read). - Organization: Members (R/W), Administration (Read). - Events: `issue_comment`, `issues`, `pull_request`. - Install on the RLadies+ org. Save the App ID, generate a private key, and install the app on every repo Jinx needs to act in. ## Wire up secrets Two values are required for every workflow: - Variable `JINX_APP_ID` — the App ID from the registration above. - Secret `JINX_PRIVATE_KEY` — the App's private key, pasted as-is. Both are read by [`actions/create-github-app-token`](https://github.com/actions/create-github-app-token) at the top of every workflow. Set them at the org level so new repos pick them up automatically. Module-specific secrets are only needed if you want that module's features. A missing module secret is not fatal — Jinx skips the module and logs a hint: | Secret | Used by | | --------------------------------------- | ---------------------- | | `AIRTABLE_API_KEY` | Airtable sync | | `BSKY_USER`, `BSKY_PASS` | Bluesky announcements | | `MASTODON_TOKEN` | Mastodon announcements | | `LINKEDIN_ACCESS_TOKEN` | LinkedIn announcements | | `SLACK_TOKEN` | Slack management | | `MAILCHIMP_API_KEY` | Newsletter | | `PLAUSIBLE_API_KEY` | Website analytics | ## Configuration files Jinx loads almost everything from data files in `inst/`, so most operational changes don't need a code release — just a PR. - `inst/config/teams.yml` — team definitions: roles, repos, notification channels. - `inst/config/review-rules.yml` — file-path patterns that drive PR reviewer assignment. - `inst/config/labels.yml` — file-path patterns that drive PR labelling. - `inst/config/conferences.yml`, `events.yml`, `languages.yml` — module-specific lists. - `inst/templates/*.md` — issue-comment replies, onboarding checklists, command help. `inst/templates/teams/.md` extends the base onboarding checklist for a specific team. - `inst/translations/` — message translations indexed by language code. Editing any of these is a normal PR. The bot image rebuild picks them up on the next push to `main`. ## Adding a new command Every `/jinx ` flows through the same two functions, defined in [`R/commands.R`](https://github.com/rladies/jinx/blob/main/R/commands.R): ```{r} cmd <- jinx::cmd_parse("/jinx invite @ada to website") jinx::cmd_execute(cmd) ``` To add a new verb: 1. Extend `cmd_parse()` so it returns the structured fields your verb needs. 2. Extend the dispatch in `cmd_execute()` to call your module function. 3. Add the command to [`inst/commands/help.md`](https://github.com/rladies/jinx/blob/main/inst/commands/help.md) so `/jinx help` finds it. 4. Cover the parser case in `tests/testthat/test-commands.R` and the module function in its own test file. That's it. The `bot-commands.yml` workflow already calls `cmd_parse` + `cmd_execute` for issue-comment triggers, and the Cloudflare Worker dispatches Slack-side calls into the same workflow. You only need to touch a workflow if your verb needs a new schedule or a separate trigger. ## Opt another repo into PR review To add Jinx's PR review to any RLadies+ repo, drop this workflow in: ```yaml # .github/workflows/jinx-review.yml name: PR review on: pull_request: types: [opened, reopened, synchronize] jobs: review: uses: rladies/jinx/.github/workflows/reusable-pr-review.yml@main secrets: inherit ``` `secrets: inherit` is how the caller repo gets `JINX_APP_ID` and `JINX_PRIVATE_KEY` from the org-level secrets — no copy-pasting. The same pattern works for `reusable-welcome-contributor.yml`, `reusable-thank-contributor.yml`, and `reusable-post-checklist.yml`. ## The bot image Workflows run inside `ghcr.io/rladies/jinx-bot:latest`, which has the package and all its dependencies pre-installed. [`infra-build-bot-image.yml`](https://github.com/rladies/jinx/blob/main/.github/workflows/infra-build-bot-image.yml) rebuilds it when `DESCRIPTION`, `Dockerfile`, or other runtime files change on `main`. That's why a typical Jinx command run finishes in a few seconds — no `install.packages` at run time. When you add a new R dependency: 1. Add it to `DESCRIPTION`. 2. Merge to `main`. 3. Wait for `infra-build-bot-image` to finish — until then, runs still use the old image and your new dependency won't be there. ## The RAG index The Slack bot answers questions by retrieving from a Cloudflare Vectorize index that's built by Jinx on a weekly schedule. That builder lives in `R/rag-*.R` and is configured by `inst/config/rag-sources.yml`. See the [RAG indexer](rag-indexer.html) article for the contributor guide — what each source does, how to add a new one, and which env vars the workflow needs. ## The Cloudflare Worker The Worker at `https://jinx.rladies.workers.dev` is Jinx's front door for Slack and Airtable. It's deployed by [`infra-deploy-worker.yml`](https://github.com/rladies/jinx/blob/main/.github/workflows/infra-deploy-worker.yml) on every push to `worker/` on `main`. Worker secrets are managed through Wrangler: ```bash cd worker wrangler secret put SLACK_SIGNING_SECRET wrangler secret put SLACK_CLIENT_ID wrangler secret put SLACK_CLIENT_SECRET wrangler secret put GITHUB_PAT ``` KV namespaces (`SLACK_TOKENS`, `AIRTABLE_BASES`) and the Vectorize index (`rladies-content`) are declared in `wrangler.jsonc` — adding one means editing that file, not running a command. For what the Worker actually does end-to-end, see [How Jinx is built](architecture.html). ## When things break - **A workflow run failed.** Open the [Actions tab](https://github.com/rladies/jinx/actions), find the red run, and read the `cli` log of the failing step. Most module functions print their own context. - **A Slack `/jinx ...` got no reply.** Tail the Worker (`wrangler tail` from `worker/`). Failures here are almost always signature verification, a missing env var, or a Slack scope that wasn't granted. - **A scheduled job didn't run.** GitHub disables scheduled workflows on inactive repos. Trigger one manually from the Actions UI and the schedule resumes. - **A new command is wired but Slack says "unknown command".** The bot image hasn't rebuilt yet — wait for `infra-build-bot-image` to finish, then try again. The audit log is the Actions run history. Logs for runs older than 14 days are gone; if you need to preserve evidence, screenshot it before the retention window closes. ## Where to go next - [How Jinx is built](architecture.html) — the surface map between R package, workflows, and Worker. - [Privacy policy](privacy.html) — what data Jinx receives, where it goes, how to request deletion. - The [function reference](../reference/index.html) — every exported function, grouped by module.