productize.blog
AI · Developer Tooling

A plugin marketplace is not just somewhere you download from. You can host your own.

You edit a file and the AI still behaves the old way, because the machine reads a copy it took at install time, not the thing you just changed. Here is how to keep your own set of tooling, how to check it actually arrived, and six places where every command prints green and nothing moves.

Yim· written with Dobby (AI Oracle)/Aug 14, 2026

You edited the file that tells your AI what to do. You saved it. You asked for the same task again, and it behaved exactly as before, as if nothing had changed.

This happens constantly, and almost every time it does not mean you edited the wrong thing. It means the edit has not reached the thing doing the work. The machine is not reading the file you edited. It is reading a copy it took when you installed.

Think of editing a document in a shared drive while the other person has the copy they downloaded last week open in front of them. You really did change it. They really are seeing the old one. Nobody is wrong; you are just looking at two different copies.

The word marketplace is misleading. It sounds like a central store somebody else opened for you to browse. It is really just a folder with an index file in it. Anyone can open one, and it is the most direct way to get the same set of tools onto more than one machine.

This post has two halves. The layout you need, which is smaller than you would expect. Then six traps we walked into ourselves, each with the date we hit it, because these cost real time rather than being things we imagined might break.

Part 1The layout you need

A marketplace needs exactly one file: .claude-plugin/marketplace.json. It carries a name, an owner, and the list of plugins with the folder each one lives in. Ours looks like this, trimmed to two entries.

{
  "name": "hello-oracle",
  "owner": { "name": "..." },
  "plugins": [
    { "name": "yim-tools",   "source": "./plugins/yim-tools" },
    { "name": "arra-oracle", "source": "./plugins/arra-oracle" }
  ]
}

Each plugin then needs its own .claude-plugin/plugin.json carrying a name, a version, and the skills it ships. Hold on to the word version. It comes back as the first trap.

Adding it to a machine is one command, pointed at either a URL or a path.

claude plugin marketplace add https://github.com/<owner>/<repo>
claude plugin install yim-tools@hello-oracle

That is the whole setup. The rest of this post is about what happens afterwards, when you change something and want the change to reach the other machine.

Why editing the file changes nothing

Because saving the file does not mean the thing doing the work got it. On install, Claude Code copies the plugin into a separate copy filed under its version number, and reads from that copy, never from the folder you edit. So you can edit, save, and send it upstream, and nothing moves, because nothing asked for a fresh copy.

What makes this worse than an ordinary stale-cache problem is the reply you get when you ask for an update. If the version in plugin.json is unchanged, the command answers:

✔ already at the latest version (1.0.1)

That sentence reads like success, not like being blocked, so you close the window and move on while the change sits where you left it. The day it caught us (Jul 28, 2026) we had edited every file, committed, and run the marketplace update, and the cache was still serving the old copy.

The fix is a single habit: bump the version in plugin.json first, every time. If you did not bump it, do not expect anything to change.

Part 2Six traps that cost us real time

Ordered by how much time each one burned. Number one is the section above, repeated so the list stands alone.

  1. Saving is not arriving. Bump the version first, or the update command reports it is already current and copies nothing across.
  2. Copying files into a flat folder does nothing. What the machine reads is the version-scoped folder. Copy your skills into a single-level folder with no plugin.json alongside them and the machine does not treat it as a plugin at all, so nothing picks it up. A whole round of work, spent for nothing.
  3. The shorthand hangs for two minutes. If you type the short form of the address (just owner/project), the tool switches to a connection method that verifies your identity first. On a machine that has never connected to GitHub that way, it prints a confirmation prompt and then waits for an answer that is never coming, until it times out. All you see is a hang with no cause. Do not answer the prompt: installing a plugin never needs that route. Type the full web address (the one starting with https) and it is gone.
  4. What looks like flakiness is usually a difference between machines. Trap 3 misled us for a while, because on the main machine the short form simply worked (that machine had connected to GitHub that way before) while a fresh machine hung every time. Averaged together that reads as "hangs twice out of five", which sounds like an unreliable tool. Once we could make it hang on demand, it stopped being random (Jul 30, 2026: 20 runs with full URLs and paths, zero hangs).
  5. Installed does not mean enabled. If that AI assistant is launched with its own settings file, you also have to write the plugin name into that file's allowed list (the enabledPlugins field). Installing it on the machine is not enough on its own. We did not guess this: we measured it with a control arm, and the agent that listed it saw 6 skills while the agent that did not saw zero (Jul 3, 2026).
  6. A check wider than the copier is a check that can never pass. The script that builds our marketplace is told to copy "everything" with a single asterisk, which leaves out files whose names begin with a dot (config files, normally hidden). The checker written later compared every file including those, so it reported the two sides as mismatched forever, with no way to ever make them match, because the copier had never been asked to move those files at all.

Trap 6 is the one we like most, because it is not a bug in the tool but a bug in where the check was drawn. A gate that checks more than the system ever promised to do will alarm forever, until nobody listens to it.

Part 3How to check it actually arrived

All six traps share one symptom: every command prints green and the thing does not arrive. The only defence is to stop reading the success message and go look at the far end instead.

We use two checks together. Ask the machine which version it currently sees, then look for the file in the cache directly.

claude plugin list
test -f <cache>/<plugin>/<new-version>/skills/<skill>/SKILL.md

The second line is the one that matters, because it asks the direct question: is the file I just edited now in the place the machine actually reads? That is a different question from whether a command exited without an error.

For one more layer, make it fail on purpose once. Point it at a version that does not exist and see whether the check goes red. If pointing it somewhere wrong still comes back green, that check was never checking anything.

Part 4The one rule to keep

If only one thing survives this post, make it this: in any system that copies, a success message tells you the source was fine. It does not tell you the destination got anything.

A marketplace shows it clearly because it copies three times over: from the file you edit, to the shared code store, to the copy on the machine, and only then to the thing actually running. Every layer can report itself fine while the next one has not moved.

This does not stop at plugins. Anywhere something is copied, synced, or shipped to a server, the shape is the same. The habit worth building is small: before you say it is done, open the far end and look once.

More in this series
Sources and references

This post is one layer of the 7 layers of a production AI agent architecture

Follow along

Get new posts and free resources first

Leave your email. New posts and the occasional free resource land in your inbox. No spam.

Email only, for updates.

Comments

Join the conversation

Share a thought.

Name is shown publicly. Email stays private and is never shown.

Loading comments…