Skip to content

Contributing to REX

REX (Research EXtensions) is an open-source framework for building Chrome and Edge browser extensions that collect behavioral data designed for academic research use. It is made up of public, reusable modules; each research study assembles its own (often private) extension by combining whichever modules that study needs, along with study-specific instructions, IRB-related language, and data collection pipelines. This guide is for researchers and their teams who want to contribute a feature or fix to one of the public modules.

Contributions tend to be accepted when they follow the architectural approach of the project and are placed in the right unit of functionality (module or package), and embody good software engineering principles (don’t repeat yourself, encapsulation, principle of least surprise, etc.).

Contributions may come from researchers with specific needs rather than professional developers. You may work with an AI coding assistant, on your own, or with a combination of both. This guide walks you through the full process.


This guide assumes basic familiarity with Git and GitHub, specifically: cloning a repository, creating a branch, committing changes, and opening a pull request. Git is the version control system that tracks changes to code over time and lets multiple people collaborate safely; GitHub is the website that hosts those repositories and manages contributions. If those concepts are new to you, work through GitHub’s Getting Started guide first.

If you prefer not to use the command line, GitHub Desktop is a free, official GUI that handles all of the above without requiring any terminal commands. It works on Mac and Windows.


REX is a collection of independent modules: each one does one thing (recording page visits, mirroring search results, blocking certain pages, etc.). Extensions for specific research studies are assembled by picking the modules that study needs. The modules themselves are shared and reusable across studies; they live in public GitHub repositories under the bric-digital organization.


Public modules (the repos you will fork and contribute to) contain generic, reusable capabilities. They must work for any researcher, any study. They contain no study-specific logic, no participant identifiers, no client names, no hardcoded URLs.

Your study extension (a private or public repository specific to your project) is where study-specific logic lives: which modules you include, how they are configured, your participant flow, any behavior unique to your study. You will never commit study-specific details to a public module, and some information should not be on GitHub at all. Make sure you make use of .env files and .gitignore (or equivalent methods) for all keys and passwords.

If your idea is useful only to your study, it belongs in your private extension repo. If it is useful to any researcher who might use that module, it belongs in the public module, and that is where you contribute it.

When in doubt: ask yourself whether a researcher at a different university running a completely different study would find this feature useful. If yes, contribute it to the public module. If no, keep it in your extension.


Two Paths: Private Fork or Public Contribution

Section titled “Two Paths: Private Fork or Public Contribution”

Once you have decided your change belongs in a public module, you still have a choice about how to incorporate it into your extension. There are two paths, and the right one depends on how urgent the work is and whether you want BRIC’s support for it.

If you have an urgent deadline or you just want to experiment without going through a formal process, you can fork the public module, make your change on a branch of your fork, and point your extension’s package.json at that branch:

"@bric/rex-page-manipulation": "github:your-org/rex-page-manipulation#your-branch-name"

This is a perfectly valid way to use REX. Your extension picks up your fork’s code directly; you do not need anyone’s review or approval before shipping. You can iterate as fast as you want.

The tradeoff: BRIC cannot support or fix problems you run into in a fork. If a future change to the upstream module conflicts with your fork, you are responsible for resolving it. If your forked code has a bug, you are responsible for finding and fixing it. Your fork will also not benefit from future fixes and improvements to the upstream module unless you actively merge them in. Other REX users will not have access to your change.

Choose this path when speed matters more than support, and you are comfortable maintaining the fork on your own.

Path B: Public contribution (slower, supported, shared)

Section titled “Path B: Public contribution (slower, supported, shared)”

If you want your change to be available to other REX users, and you want BRIC to review it, support it, and carry it forward as the upstream module evolves, open a pull request against the public module. This is the path the rest of this guide walks through.

The tradeoff: PRs are reviewed by the BRIC team, which takes time and may require revisions before merging. The bar is higher because the change has to make sense for every researcher using that module, not just your study. In exchange, your change becomes part of the official module, BRIC’s support covers it, and future contributors build on it.

Choose this path when the change is general-purpose, when you are not under acute deadline pressure, or when you want the long-term maintenance burden off your plate.

It is also reasonable to ship via Path A first (pin your extension to your fork to meet a deadline) and then open a PR for the same change (Path B). If the PR merges upstream, you switch your extension’s package.json back to the official module and retire your fork. This is a common pattern and a good way to balance urgency with contribution.


Example: Adding Scroll Depth to Page Events

Section titled “Example: Adding Scroll Depth to Page Events”

Here is a concrete example of the full process for contributing a new feature. It assumes you have already decided the feature belongs in a public module (see “The Public/Private Split”) and that you want to go through the public contribution path (Path B from “Two Paths”). If you only need this for your own study and are short on time, the same exploration steps still apply; you just stop before opening a PR and pin your extension’s package.json at your fork instead.

The idea: A researcher wants to know not just how long participants stay on a page, but how far down they scroll, so they can tell a quick skim from a full read.


Step 1: Write down a real description of the feature before doing anything else.

A one-line title is not enough. Before you clone repos or open editors, answer these:

  • What it does: Records how far down each page the participant scrolls, as the deepest point reached (a percentage of the page’s height), reported when the participant leaves the page.
  • Who it is for: Any researcher studying attention or reading, such as a news exposure study that needs to separate skimming headlines from reading articles.
  • What triggers it: Scrolling on a page; the deepest point is summarized when the page is hidden or closed.
  • What data it touches or produces: Reads the page’s scroll position and height, and adds a scroll depth value to page events. It does not read page content.
  • Which sites or contexts it applies to: Every page rex-page-events already records, with the same list-based redaction.
  • Why existing modules cannot do this: rex-page-events records focus and dwell time but not scroll position, and no other module reads it.

Step 2: Set up a working directory and a starting set of clones.

Make a single folder on your computer. The minimum starting set is rex-core (read-only context: every module depends on it) and rex-types (shared types you may reference). Beyond that, scan module-map.md against the feature description and clone every module that could plausibly host this feature.

Then place the AI context files at the root of that folder:

If you are using…Do this
ClaudeCopy AGENTS.md to the root as CLAUDE.md
GeminiCopy AGENTS.md to the root as GEMINI.md
Cursor, Copilot, or another toolCheck your tool’s documentation for its context file name, or paste the contents of AGENTS.md as your first message
Working independentlyRead AGENTS.md yourself; it documents key REX conventions

Download AGENTS.md (or read it on Working with an AI Assistant). It should be placed at the root of your working directory so your AI assistant reads it automatically.


Step 3: Run an exploratory session before writing any code.

The goal of exploration is to find the right module and the right level of generality. This is the hardest part of the contribution (see Getting Placement Right), so do not rush it.

If you are working with an AI assistant, after giving it the feature description from Step 1, prompt it like this:

Now that I have described the feature, please explore all the repositories in this directory in depth to determine: (1) which module is the right place for this feature, (2) at what level of the hierarchy it should live: aim for the highest level of generality that is still appropriate, without going so high that the module takes on responsibilities that do not belong to it, (3) whether any similar functionality already exists that we should build on or extend rather than duplicate, (4) whether any part of this feature is study-specific and belongs in my private extension repo instead of a public module. Read the actual source files, not just READMEs. Report your findings and propose an approach before we start implementation.


Step 4: Reach a placement decision you can defend in one sentence.

Whichever way you decide, the test is the same: can you say in one sentence which module is the home, why that level is the highest appropriate one, and why no existing functionality already covers it? If yes, you are ready to write code. If not, keep exploring or ask BRIC at info@bric.digital before committing to a direction.


Step 5: Fork, branch, build, and (if going Path B) open a PR.

  1. Fork the target module on GitHub.
  2. Create a branch for your feature (e.g., feature/scroll-depth).
  3. Make your changes, with or without AI assistance.
  4. Test your changes by pointing your extension’s package.json at your branch. Then build that extension and load the unpacked dist/extension/ folder in Chrome or Edge.
  5. If you are on Path A (private fork only): you are done with this module. Point your study extension’s package.json at your branch and ship.
  6. If you are on Path B (public contribution): push your branch to your fork, run through the PR checklist, and open a pull request on the BRIC repository.

Before your first contribution can be merged, you will be asked to sign a Contributor License Agreement (CLA). A CLA is frequently a part of open-source projects: it clarifies that you have the right to contribute the code you are submitting and that BRIC has permission to include it in the project. It does not transfer ownership of your work. We use the CLA assistant to make the process as quick as possible, and you only need to do it once.

Once your PR is open, the BRIC team will review it. We may have questions: about the placement, the API, the test coverage, or how the change interacts with other modules. Respond in the PR thread; quick back-and-forth helps a PR land. If we ask for a change you disagree with, push back with technical reasoning rather than silently agreeing or silently ignoring.

The PR checklist captures the specific things to verify before opening a PR. Run through it before you hit “Create pull request.”


  • Email: info@bric.digital
  • Getting placement right: Getting Placement Right: the single hardest decision in a REX contribution, and the #1 reason PRs get sent back. Read this before you start.
  • PR checklist: PR Checklist: run through this before opening a pull request.
  • Module reference: Module Map: use this to find where your feature belongs