You built something worth paying for and put it in a private GitHub repo. Now you have to actually sell access to it: take money, add the buyer as a collaborator, hand over a deploy token, and remember to pull all of that back when they stop paying. Most people wire this together by hand with a Stripe webhook, a shell script, and a spreadsheet. It works until you have twenty customers and someone cancels while you are asleep.

GHRM ("GitHub Repo Manager") is the part of the VBWD platform that does this for you. It turns a GitHub repository into a subscription-gated product: a plan on the billing side, a catalogue page on the storefront, and a set of GitHub API calls that grant and revoke access as subscriptions come and go. This is a walk through what it does, where the boundaries are, and what it will not do for you.

What GHRM actually is

VBWD is a self-hosted, source-available platform: Python/Flask with PostgreSQL on the back, Vue 3 on the front, all in Docker. The core is deliberately agnostic. It knows about users, plans, subscriptions, invoices, and an event bus. It does not know what GitHub is, and it never will. Everything domain-specific lives in plugins, and plugins extend the platform by listening to events on the bus rather than editing core code. If you want the longer version of that split, the architecture overview explains why the core stays out of your business logic.

GHRM is one of those plugins (packaged as a bundle you install and configure). When a subscription becomes active, the core emits a subscription.activated event. GHRM subscribes to that event and does the GitHub work: it looks up which packages the plan grants, issues deploy tokens, and invites the customer as a collaborator on the relevant repositories through the GitHub API. When the subscription is cancelled or expires, the core emits the corresponding events, and GHRM revokes access after a grace window. The core moved money and changed a subscription state. It has no idea a repo was involved. You can browse it and the rest of the catalogue on the plugins page.

That separation matters for two reasons. First, your billing, tax, and invoicing logic is shared with every other VBWD plugin, so GHRM is not reinventing subscriptions. Second, if GitHub changes its API or you decide to distribute through a different channel, the blast radius is one plugin, not your whole platform.

The subscription-to-access lifecycle

The useful mental model is a state machine driven by events, not by cron jobs polling a payment provider.

Define the catalogue. You describe a set of packages, each tied to one or more plans. A package points at a GitHub repository (or several) and the access it grants. A plan can bundle multiple packages; a package can appear in multiple plans. This is data, configured through the admin, not code.

Activation. A customer subscribes and pays. The core fires subscription.activated. GHRM resolves the plan to its packages, then for each repo it calls the GitHub API to add the customer as a collaborator and issues any deploy tokens the package defines. The customer now has real, revocable access tied to their own GitHub account.

Renewal. Nothing dramatic happens. The subscription stays active, access stays granted. Because access is tied to subscription state rather than a one-time grant, you never have to reconcile "who paid last month" by hand.

Cancel or expiry. The core emits the cancel/expiry event. GHRM does not yank access instantly. It waits out a configurable grace window, then revokes the collaborator invite and invalidates the deploy tokens. The grace period is deliberate: it absorbs failed-then-retried payments and gives a lapsed customer a short runway rather than a hard cliff mid-workday.

All of this rides the subscription lifecycle events the platform already publishes. GHRM adds no new billing concepts. That is the whole point of building on an event bus: the monetisation logic is generic, and the GitHub-specific reactions are bolted on at the edges. The documentation covers how plugins subscribe to these events if you want to see the shape of it.

The release and sync side

Selling access is half the job. The other half is keeping the storefront honest about what customers are getting. GHRM syncs repository metadata into the platform: it pulls README, CHANGELOG, and release information via GitHub Actions and surfaces them on a catalogue page rendered through the CMS.

Practically, this means your product page is not a stale marketing blurb you forgot to update three releases ago. When you cut a release on GitHub, the Action pushes the new CHANGELOG and release notes into VBWD, and the catalogue page reflects it. The README becomes the product description. Buyers see what the current version does, and what changed, without you copy-pasting notes between two systems.

Because the catalogue page is a CMS page, it behaves like any other content on your site: you can style it, embed it, and link it into your navigation. The sync fills in the product-specific parts; the CMS owns the presentation.

A worked example: selling access to a private repo

Say you maintain acme-org/telemetry-sdk, a private repo, and you want to sell a "Pro" tier that grants read access plus a deploy token for CI use.

1. Configure the GitHub App. GHRM talks to GitHub through a GitHub App (with an OAuth flow for the customer side). You register an App, give it access to your org, and drop its PEM private key where the plugin expects it. This is the step that most often goes wrong, so it is worth doing carefully — more on that in the limits below.

2. Create the plan. In VBWD you create a "Pro" plan with whatever price and billing interval you want. This is a normal subscription plan; nothing GitHub-specific lives here. Pricing models the platform supports are described on the pricing page.

3. Define the package. You create a GHRM package that points at acme-org/telemetry-sdk, sets the collaborator permission to read, and declares a deploy token. You attach the package to the "Pro" plan.

4. Publish the catalogue page. GHRM syncs the repo's README and CHANGELOG and produces a catalogue page. You edit it in the CMS, add a buy button pointed at the Pro plan, and publish.

5. A customer buys. They subscribe, pay, and connect their GitHub account through the App's OAuth flow. On subscription.activated, GHRM invites their GitHub account as a read collaborator on telemetry-sdk and issues the deploy token. They accept the invite and clone. Their CI uses the token.

6. They cancel. Two months later they cancel. The subscription enters its end state, GHRM starts the grace timer, and when it elapses the collaborator invite is removed and the deploy token is invalidated. They lose access to new pushes and releases.

At no point did you touch a terminal. You configured data and let the events do the work.

Honest limits

GHRM is a thin, well-behaved layer over GitHub, and it inherits GitHub's constraints. Be clear-eyed about them before you build a business on it.

It gates ongoing access, not copies already made. This is the big one. Once someone has cloned your repo, that clone is on their disk forever. Revoking their collaborator status stops them from pulling future commits and releases, and cuts off their deploy token. It does not reach into their machine and delete what they already have. What you are selling, in practice, is continued updates and legitimate access — not a copy-protection scheme. Price and message accordingly.

Revocation is after a grace window, not instant. By design. If you need a hard, immediate cut-off the moment a card fails, this is not that. The grace period exists to avoid punishing customers for transient billing hiccups.

You are bound by GitHub's collaborator model and rate limits. Access is per GitHub account, granted through invites the customer must accept. Bulk operations are subject to GitHub's API rate limits. At small and medium scale this is a non-issue; at very large scale you plan around it.

The GitHub App must be configured correctly or invites fail. The PEM key's filename and path have to match what the plugin reads, and the App has to have the right visibility and org access. A private App that should be public, or a misnamed PEM, produces invites that 404 with no obvious cause. When something silently does not work, this is the first place to look.

None of these are bugs. They are the shape of distributing software through GitHub. GHRM does not pretend otherwise, and neither should your sales page.

Takeaway

If your product is code in a private repo, GHRM lets you sell access to it without hand-rolling the plumbing. You define a catalogue, tie packages to plans, and let subscription events grant and revoke GitHub collaborator access and deploy tokens automatically, with a grace period on the way out. The catalogue page stays current because releases sync in through Actions. And because the core is agnostic, none of this GitHub logic contaminates your platform — it is one plugin reacting to events. VBWD itself is source-available under BSL 1.1, free for commercial use while your annual VBWD-attributable sales stay under the value of 6.7 BTC, so you can run the whole thing yourself and read every line.

Next step: read the GHRM configuration guide in the docs before you register your GitHub App — getting the PEM path and App visibility right the first time saves you a round of 404s.