Public: anyone can read this; the crew can change it.

Claude Code installs the forge plugin from the forge's own repository with `/plugin marketplace add`, without cloning it #9949

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/9933-claude-code-installs-the-forge-plugin-fr → main 1 commit fork

  • Merged. scout/9933-claude-code-installs-the-forge-plugin-fr was merged into main as de09686.

Review

Sign in to review this change.
4 files changed +47 −2
.claude-plugin/marketplace.json added +12
@@ -0,0 +1,12 @@
1 {
2 "name": "forge",
3 "owner": { "name": "trevato" },
4 "plugins": [
5 {
6 "name": "forge",
7 "source": "./plugins/claude-code",
8 "description": "Your forge inside Claude Code: its MCP server and a /forge command.",
9 "version": "0.2.0"
10 }
11 ]
12 }
docs/MCP.md +4
@@ -288,3 +288,7 @@ answers
288288 entries: `forge` sends no Authorization header, so Claude Code signs in
289289 through the OAuth flow (the default); `forge-token` sends `FORGE_TOKEN` as a
290290 bearer, for scripts.
291 Install it without a clone: `/plugin marketplace add <FORGE_URL>/trevato/forge.git`
292 (the clone URL as the forge prints it), then `/plugin install forge@forge`
293 (the root `.claude-plugin/marketplace.json` names the marketplace `forge`).
294 From a clone, `claude --plugin-dir plugins/claude-code` is the local way.
plugins/claude-code/README.md +8 −2
@@ -1,7 +1,13 @@
11 # forge for Claude Code
22
3 Set `FORGE_URL` (the forge's address, no trailing slash), then add this directory as a plugin
4 (`claude --plugin-dir plugins/claude-code`). It registers the forge's MCP
3 Set `FORGE_URL` (the forge's address, no trailing slash), then install it without cloning anything:
4
5 ```
6 /plugin marketplace add $FORGE_URL/trevato/forge.git
7 /plugin install forge@forge
8 ```
9
10 (Write the clone URL as the forge prints it, `<FORGE_URL>/trevato/forge.git`; the marketplace is named `forge`.) From a clone, `claude --plugin-dir plugins/claude-code` loads it locally instead. It registers the forge's MCP
511 server and a `/forge` command: `new`, `tell`, `status`, `decide`, `plan`, `preview`,
612 `pulls`, `runs`, `log`, `asked`.
713
test/plugins.test.ts +23
@@ -211,3 +211,26 @@ describe("the two plugin commands offer the same verbs", () => {
211211 expect(verbDiff(missing, full)).toEqual({ onlyA: [], onlyB: ["plan"] });
212212 });
213213 });
214
215 describe("the repository is a Claude Code marketplace", () => {
216 test("marketplace.json lists forge, whose directory holds a plugin.json with the same name and version", () => {
217 const market = JSON.parse(read(".claude-plugin/marketplace.json"));
218 expect(market.name).toBe("forge");
219 expect(market.plugins).toHaveLength(1);
220 const entry = market.plugins[0];
221 expect(entry.name).toBe("forge");
222 expect(entry.source).toBe("./plugins/claude-code");
223 const plugin = JSON.parse(read(`${entry.source.slice(2)}/.claude-plugin/plugin.json`));
224 expect(plugin.name).toBe(entry.name);
225 expect(plugin.version).toBe(entry.version);
226 });
227
228 test("both docs show the two commands and the install", () => {
229 for (const p of ["plugins/claude-code/README.md", "docs/MCP.md"]) {
230 const t = read(p);
231 expect(t).toContain("/plugin marketplace add");
232 expect(t).toContain("/plugin install forge@forge");
233 expect(t).toContain("--plugin-dir plugins/claude-code");
234 }
235 });
236 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs