All posts

Renaming a published plugin is safe until you reuse the name

Two plugins of ours have been in Obsidian's community directory since June. Yesterday we renamed both of their repositories, which is the kind of change you are told not to make to something people have installed.

Nothing broke. That part is measurable and I will show the measurements. What is worth writing down is the shape of what *would* break, because it is not the part anybody worries about — and, at the end, the two readings of this system that sent the work in the wrong direction, both of which were completely reasonable at the time.

The change

`CVERInc/marktile` became `CVERInc/obsidian-marktile`, and the same for its sibling. A prefix rather than a suffix, because that is the convention the Obsidian ecosystem already uses — `obsidian-dataview`, `obsidian-excalidraw-plugin` — and because the bare name belongs to the product rather than to one of its delivery surfaces.

The manifest `id` did not change and must never change. It names the folder the plugin is installed into. Changing it orphans every user's settings, which is a much worse thing than anything discussed below.

What Obsidian actually fetches

The directory stores a `repo` string. Everything else is derived from it, so the question "does a rename break my plugin" reduces to "does each of those fetches survive". There are three, and they do not behave the same way.

The manifest, read from the default branch:

$ curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \
    https://raw.githubusercontent.com/CVERInc/marktile/main/manifest.json
200

Two hundred, with no redirect at all. `raw.githubusercontent.com` resolves the old path directly. There is nothing for a client to follow, so no client can fail to follow it.

The release, and its assets:

$ curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \
    https://github.com/CVERInc/marktile/releases/latest
301 https://github.com/CVERInc/obsidian-marktile/releases/latest

One redirect, which any ordinary HTTP client follows. That is the only hop in the whole chain.

The measurement that counts

All of the above proves the components resolve. It does not prove the channel works, and those are different claims — a distinction I have got wrong often enough to be careful about.

So we cut a real release after the rename. Version 0.2.0 of both plugins, while the directory still held the old `repo` string. Then a phone and a tablet running Obsidian were asked to update.

Both did. The plugin page showed `Version: 0.2.0 (currently installed: 0.2.0)` and, directly underneath, `Repository: https://github.com/cverinc/marktile` — the old path, still.

That is the answer. Not the curl output: the install.

The one thing that breaks

From GitHub's own documentation on renaming:

If you create a new repository under your account in the future, do not reuse the original name of the renamed repository. If you do, redirects to the renamed repository will no longer work.

This is the whole risk, and it arrives long after the rename, in an unrelated piece of work. The directory still points at the old name. The moment something *else* occupies that name, the pointer stops being a redirect and starts being a destination — one with no `manifest.json` and no releases. Every installed copy of the plugin then asks a repository that has never heard of it.

Note also that a repository name is claimed from a single namespace regardless of visibility. A *private* repository with the old name takes it just as completely as a public one, and does the same damage, invisibly.

Which means the bare name is not free yet, and the sequencing is fixed: rename, then get the directory repointed, and only then reuse. Not the other way round.

The directory does not repoint itself

It also does not let you repoint it. The listing editor covers description, pricing, icon and screenshots, and nothing else; I enumerated every input on the page rather than looking for the one I wanted and concluding it was absent.

The registry file in the public `obsidian-releases` repository is not the source either — its commits read `chore: Mirror community plugins and themes`, so it is a mirror of a database that lives behind the submission portal, and pull requests against it are closed.

The channel turns out to be the forum, which we only found by looking for someone with the same problem. An Obsidian staff reply on a thread about an organisation rename says it plainly: it is a manual process on their end for now, and they did it for the person who asked. So we asked. That is still outstanding as this goes up.

The same wrong move, twice, from both ends

Everything above is downstream of two readings that were confidently wrong, and they are worth laying next to each other because they are the same error wearing different clothes.

**A search that returned nothing.** Whether the rename was cheap depended on whether the plugins were already listed. I filtered the registry for `CVERInc`, got zero results, and reported that they were not — which made the change look free, and made the recommendation that followed the opposite of correct. The registry stores the owner in lower case. Our own release runbook stated on its first page that both had been listed since June; I had opened that file ten minutes earlier for something else.

**A link that arrived at the right place.** Later that evening the directory's own menu for one of the plugins offered **View on GitHub**, and it landed on the renamed repository. Reasonable grounds for concluding the directory had caught up by itself.

It had not. The `href` was `https://github.com/cverinc/marktile`. GitHub carried the click the rest of the way. The address bar showed the new name because a redirect had fired, not because anything had been updated.

One of those readings was mine and one was not, and the distinction turns out not to matter much: a zero result and a successful click are both renderings, and neither is a statement about the thing that produced it. Both readings were also perfectly faithful. Nothing lied.

What actually resolved it

Not argument. In both cases the disagreement was settled by finding an instrument that could only return one answer.

For the listing question, that was the registry's own spelling. On the plugin's page, `cverinc/marktile` in lower case is emitted by the directory from its stored string; `CVERInc/obsidian-marktile` in mixed case occurs twenty-four times and is all our own README, which the directory renders but does not author. One command counting two spellings decides a question that looking at the page cannot decide at all, because the page shows both and marks neither.

For "does releasing still work", it was a device. Not a status code — a phone completing an install.

That is the whole working method, and it has an uncomfortable property: it is much easier to apply to someone else's claim than to your own. Each of these took hours to surface and about a minute to settle once somebody asked what could be measured instead of what sounded right. The expensive part is never the measurement. It is the interval before anyone thinks to take one.

Keep reading

Notes from the workshop — the door is open.