In the previous post and the one before it, I wrote about modifying Claudian, a Claude plugin for Obsidian (by Yishen Tu, MIT license). One fix to text input, and eight changes that rebuilt the tab UI. I run all of them as a fork: a copy of the official source code on my machine, with my own changes stacked on top as a separate line.
The hard part of running a fork is not writing the modifications. It is the setup that keeps your changes alive while upstream keeps updating. This post is about that.
Keep it in the fork, or send it upstream?
First, not every change belongs in the fork. The test is simple: “Is this change right for every other user too?”
- Send upstream: the fix for the bug where the Enter that confirms a Japanese IME conversion sends the message by mistake. It helps every Japanese, Chinese and Korean user, and it is right for everyone. A change like this is a candidate for a pull request to the original project
- Keep in the fork: UI changes tuned to how I work, such as turning the tab list into a drawer. Sending upstream a change that other users may not want only makes trouble for the maintainer
Checking the license before you modify or redistribute is a must. Claudian is MIT licensed, so you are free to modify it as long as you keep the copyright notice.
The daily workflow: tell source from build output
The basic routine looks like this.
- Clone the official repository locally and edit
src/ - Build with
npm run build - Copy the build output (
main.js,styles.css,manifest.json) into Obsidian’s plugin folder - Turn the plugin off and on again to load it
Where I failed once was telling source from build output. I edited styles.css at the root of the repository directly, and my change disappeared at the next build. That file was build output, generated by concatenating the CSS modules under src/style/. When you touch someone else’s repository, check first: “was this file written by a person, or made by a machine?” The quick way is to see whether the build output is listed in gitignore.
I keep running the tests and the type check on the fork as well. The key is to record, as “known differences”, the places where the existing tests disagree with my modifications. Then, when I add a new change, I do not confuse “errors that were already there” with “what I just broke”.
The biggest risk: being overwritten by an official update
The worst accident with a fork is the app’s own plugin updater overwriting it with the official version. If you apply a plugin update in Obsidian, the customized main.js is replaced by the official one, and every modification is gone.
I do not try to make this “never happen”. I prepare so that I can recover in a few minutes when it does.
- The real copy always lives in the git repository. I treat the files in the plugin folder as disposable copies
- To take in a new official version, I merge with
git pull, rebuild, and deploy again - I also keep a full set of the unmodified official files in a backup folder, so that I can roll back
Talking with what the original design left behind
As modifications pile up, there comes a moment when the original design and your changes stop fitting together. A real example: this plugin had a rule, “hide the list when there are fewer than two tabs”. When the list was shown inline, that was a sensible way to save space. But after I turned the list into a drawer, the rule became a puzzling behavior: reduce the tabs to the last one, and the drawer was forced shut and its open button vanished with it.
Finding the code responsible and deleting it is easy. But if you first ask “why was this rule put in?”, the decision changes from a plain deletion to “the list is a drawer now, so the assumption behind this rule is gone, and it can be removed”. Modifying is a conversation with the original designer. A change you remove after understanding its intent does not come back to bite you.
Which copy is the real one? Trace back from the running binary
Last, a slightly unusual kind of trouble. When I moved to a new computer, the repository for this fork was left behind inside a migration archive, and I no longer knew “which source is the correct one for the plugin that is running in Obsidian right now”.
The way I identified it was to build the repository found in the archive and compare the md5 hashes of its output with the plugin files that were actually running. They matched exactly, which settled it: this was the correct source. I put the repository back where it belongs. Unlike an official release, a fork exists in only one place in the world, so having a way to identify the real copy is a form of insurance.
Summary
- Sort changes by “is it right for everyone?”: upstream, or the fork
- Tell source from build output, and always keep the real copy in git
- Do not try to prevent official updates from overwriting your files. Accept it, in a form you can recover from at once
- Before you remove an original rule, understand why it was put there
At oobe I also help extend and maintain open source tools to fit how a business works. If you use a tool that is “handy, but not quite right for the way we use it”, write to me through the contact form.