Extraction with a Footnote

On being sniped by an LLM pointed at my open source work

open source
rstats
ai
posit
Author

James Balamuta

Published

May 3, 2026

Last week, a Senior Software Engineer at Posit merged a pull request that added portable, relocatable macOS and Windows R builds to a Posit-maintained build repository. Until very recently, the repository’s scope was Linux Docker images of R. Two weeks before this PR, the repo gained a Portable Linux build (using a different mechanism from my own prior R-in-AppImage experiments); that change also introduced a CLAUDE.md at the repo root. This PR extends both: macOS and Windows targets in a structure that mirrors, stage by stage, work I had published a month earlier, and a CLAUDE.md now expanded to cover all three platforms.

At the bottom of the PR description, under a heading called “Existing art for reference,” there are two hyperlinks. They both go to repositories I maintain. The merged macOS and Windows subdirectories each carry a “Related projects” paragraph that calls my work an “independent prototype” and credits Posit with adding “Developer ID signing” on macOS and “the innoextract+silent-install fallback chain” on Windows.

Both are false. My macOS releases have shipped with Developer ID signing and Apple notarization since April 1. My Windows build uses innoextract as its primary extractor and falls back to /VERYSILENT /CURRENTUSER exactly the way the merged code does. Posit’s macOS binaries, today, are not notarized.

This isn’t a story about being uncredited. It’s a story about being credited in a paragraph that reattributes my engineering to Posit and labels my shipped work a prototype. Their own README is the exhibit.

Screenshot of part of a GitHub pull request, merged with 19 commits, adding portable macOS and Windows R builds to a previously Linux-only build repository. A Files changed table lists paths and descriptions including macos/build.sh, macos/patch-mach-o.sh, macos/make-relocatable.sh, macos/install-rprofile-hook.sh, macos/notarize.sh, macos/entitlements.plist, macos/test.sh, windows/build.ps1, windows/test.ps1, several GitHub Actions workflow YAML files, a Makefile, README.md, and a CLAUDE.md labeled Developer notes. Below the table is an Existing art for reference section linking to two external repositories.

The Files changed table from the merged pull request. A CLAUDE.md sits at the root of the repository, alongside scripts for relocation, codesigning, notarization, and an Rprofile.site hook. The “Existing art for reference” section at the bottom links to two external repositories I maintain.

Screenshots from the PR thread are archived here.

A month earlier

Portable R for macOS and Windows had been a dormant problem for years. The R Project ships installers; the installers assume fixed paths; the binaries are not relocatable; and the working groups responsible for them were not particularly motivated to change that. Community interest goes back to a 2009 R-devel proposal. Nothing came of it for over a decade.

I picked the problem up because I needed it solved. I was building a desktop Shiny application packaged as an Electron app, and there is no way to ship that kind of app without a portable R runtime alongside it. Shiny is a Posit project. The portable R infrastructure I built in order to put a Posit-owned product on the desktop was infrastructure Posit had not built themselves and was, apparently, not going to.

I shipped the Windows project on April 1, 2026 and the macOS project on April 2, 2026. Both arrived with announcement blog posts, working binaries across twelve R versions, complete documentation, signed and notarized artifacts on the macOS side, and a release pipeline. Anyone in the rstats ecosystem searching for “portable R” or “relocatable R binaries” found them in a single click.

I am quite confident at least one Posit engineer did.

Stage by stage

This is the part I want anyone reading to look at carefully, because the structural overlap is the whole argument.

On macOS, my project does the following. It rewrites Mach-O load commands to use @executable_path and @loader_path references. It patches bin/R, Rscript, and Makeconf with BSD sed. It carries a hardened runtime entitlements file. It codesigns the result with a Developer ID certificate and submits the binary to Apple’s Notary Service. And it ships a hidden .portable R environment that attaches to the search path at startup and wraps install.packages() so that the embedded framework paths inside CRAN binary .so files are patched immediately after installation. The output of a fresh package install on portable R looks like this:

> install.packages(c("jsonlite", "curl", "httr2"))
Portable R: patched 11 shared libraries

The PR’s macOS pipeline does the following. It rewrites Mach-O load commands and codesigns via macos/patch-mach-o.sh. It patches bin/R, Rscript, and Makeconf with BSD sed via macos/make-relocatable.sh. It carries an entitlements.plist for the hardened runtime. It ships a notarize.sh script for Notary Service submission. And it installs an Rprofile.site hook via macos/install-rprofile-hook.sh.

That last one is the giveaway.

The install.packages() wrapper that patches binary CRAN packages on the fly is the most distinctive technical element of my work. It is not how Homebrew solves macOS portability. It is not how conda-build solves it. It is not how python-build-standalone solves it. None of those projects have to deal with a package ecosystem whose binary artifacts carry the same baked-in framework paths the runtime does. R does, and the wrapper is the trick I designed to handle it.

The PR’s install-rprofile-hook.sh is not a parallel discovery of the same idea. It is the same idea named the same way. Follow-up commits to the PR confirm that the hook installs an R environment named .portable, which wraps install.packages() to patch the framework paths in CRAN binary packages, and which hooks stats:attach to re-attach itself at search-path position 2 if anything tries to displace it. Same name. Same function. Same mechanism.

On Windows, the comparison is shorter because Windows is structurally simpler. My build is a single PowerShell script that uses innoextract to unpack the CRAN installer without running it (with a /VERYSILENT /CURRENTUSER fallback that cleans up unins* artifacts), then appends portable-R hooks to the base Rprofile to set up a portable site-library and default CRAN repo. The PR ships windows/build.ps1 for the build and windows/test.ps1 for tests, using the same innoextract-with-silent-fallback pattern.

None of these techniques are individually proprietary. Mach-O relocation is documented by Apple and implemented by Homebrew, conda-build, and python-build-standalone. Inno Setup silent-mode flags are documented by Inno Setup. What is mine is the specific composition: this exact stack, in this exact order, with this exact install.packages() wrapper, producing a portable R the rstats ecosystem can actually use today. That composition arrived at a Posit-maintained repository a month after I published it, in a PR built with the help of an LLM, with the original work credited as “reference” in the PR footer and “independent prototype” in nested READMEs.

That is extraction with a footnote, and I am going to keep calling it what it is.

The verb to posit means to set firmly, to assume or affirm, to propose as explanation. Posit took the verb for a name. What Posit posited last week was that my work was “reference.” Readers can decide which definition fits.

Ship it correctly or don’t ship it

I would have less to say about all of this if the result were excellent. It is not.

The PR ships a script called notarize.sh. The macOS binaries that the PR produces are not, in fact, notarized. Every user who downloads them will hit a Gatekeeper warning on first launch. A meaningful percentage of those users will assume the binary is broken or untrustworthy and walk away.

Re-read that. A senior engineer at a public benefit corporation whose entire brand is built on open source data science shipped portable R builds for macOS that Apple’s own security model flags as untrusted on first launch. The script that would solve this is in the same pull request. It was either not run, or run incorrectly, and the binaries went out the door anyway. My releases, all twelve of them, are signed and notarized.

If you are going to take someone’s work, at least ship it correctly.

The asymmetry

I have already heard, privately, from other maintainers who recognized themselves in this story. Several have pulled work behind logins or stopped publishing. The rational response to “your public repo is now training data and lookup material for a competitor’s senior engineering team” is to stop publishing public repos. I understand the reasoning. I am not there yet.

But here is the asymmetry I want every engineering leader at every well-funded data science company to sit with:

Posit is a well-funded public benefit corporation with a brand built entirely on open source contributions to the R ecosystem. I am one person who has to be strategic about which projects I invest my time in, because those projects are how I find clients and pay rent. When that asymmetry plays out the way it did here, the message to every independent maintainer in this ecosystem is clear: your work is a free R&D pipeline for the incumbent, and the incumbent’s respect for your contribution is a hyperlink and a footnote.

That is not a sustainable equilibrium. It is the equilibrium where the commons gets quietly privatized one snipe at a time, and where the next person who might have built the next useful piece of infrastructure decides to put it in a private GitLab instance and call it a day.

Fin

I am not owed anything by Posit, and I am not asking for anything from them either. The Posit engineers and leaders who chose how this went down know how to find me; many of them already follow me on Bluesky and LinkedIn, and this post will land in their feeds whether they want it there or not. The time to write a different ending was a month ago, when the project was active, public, and one search away from anyone curious enough to look.

The work is still public. The work is still mine.