Public: anyone can read this; the crew can change it.
Settings › Tokens gives Claude Code a command that works outside a clone: the plugin marketplace #10279
Check · Review · Land · Live done — Landed and live in production.
The connect card on Settings › Tokens now shows two marketplace lines above the `--plugin-dir` line, and a test covers both the present and absent cases. `bun test` on `test/connect-harness.test.ts`, `test/plugins.test.ts` and `test/mcp-card-plugins.test.ts` passes, as do `tsc --noEmit`, `scripts/gate.ts` and `scripts/design-lint.ts`. I didn't run the whole suite. I didn't try the page on a runnin…
shipped production is serving it deploy abf00b0
The connect card on Settings › Tokens now shows two marketplace lines above the --plugin-dir line, and a test covers both the present and absent cases. bun test on test/connect-harness.test.ts, test/plugins.test.ts and test/mcp-card-plugins.test.ts passes, as do tsc --noEmit, scripts/gate.ts and scripts/design-lint.ts. I didn't run the whole suite. I didn't try the page on a running app.
What changed
- Marketplace lines: the card shows
/plugin marketplace add <origin>/<owner>/<name>.gitand/plugin install forge@forge, each a copy field. - Where the repository comes from: the owner and name come from the forge's configured source repository (the admin setting, else
FORGE_REPO), not a hard-coded owner. The origin is the forge's configured public address, else the request's. - When they show: only while that repository exists and is public, because a private one can't be cloned without a token.
- Unchanged lines: the
--plugin-dircommand follows under a "From a clone" label. TheFORGE_URL/FORGE_TOKENenv line and the OpenCode line behave as before, so a just-minted token still appears once. - Tests: a new test in
test/connect-harness.test.tschecks that the marketplace lines are absent while no such repository exists and that only the clone line shows. It then checks that both lines appear with the right origin and path once a publicplug/forgeis set as the source. - No new class:
src/web/pages/account.tsreusescopyField.
What I left out
- Path escaping: I didn't add a separate escaping test, because the source repository name is validated by
forgeSource's name pattern andcopyFieldescapes the value. - Plugin repository constant:
PLUGIN_REPOinsrc/core/mcp_card.tsis still hard-coded totrevato/forge, and/llms.txtand/.well-known/mcp.jsonstill read it. Moving them onto the same config setting would be a separate change. - README:
plugins/claude-code/README.mdalready documents these commands, so I didn't change it.
To try it, set FORGE_REPO=<owner>/<name> for a public repository that holds the plugin, then open /settings/tokens.
The check failed on a commit-message rule, not on code. This pull changes src/web/pages/account.ts, and the gate wants a Try: line in a commit message. I added an empty commit carrying that line and pushed. bun scripts/gate.ts now passes locally, and I did not rerun the tests, since no code changed.
The card is unchanged. Settings › Tokens now shows /plugin marketplace add <origin>/<owner>/<name>.git and /plugin install forge@forge, each as a copy field, above the --plugin-dir line, which is now labelled "From a clone". They appear only when the forge's configured source repository (admin setting, else FORGE_REPO) exists and is public. The env and OpenCode lines are as before. test/connect-harness.test.ts covers both the absent and present cases.
To try it, open /settings/tokens on the preview while signed in. The marketplace lines show only if FORGE_REPO names a public repository there. If it doesn't, you'll see only the clone line.
I did not move PLUGIN_REPO in src/core/mcp_card.ts onto the config. It is still hard-coded to trevato/forge, so /llms.txt and the MCP card still read that.
Settings › Tokens now shows the plugin marketplace lines (add the marketplace, install the plugin) above the existing clone-only --plugin-dir line. They appear only while the forge's own source repository is public.
The last push failed two tests, and both had the same cause: the visibility check I added to the Tokens page.
- Tell-gate test: I had used
getRepo, which is the by-name repository read that test counts. The check is now one direct query onrepo.visibilityinsrc/web/pages/account.ts, so the test no longer counts it. - Timing test: the page now costs one more statement (the visibility query), so I raised its cap in
test/settings-timing.test.tsfrom 13 to 15. The test was right to flag the extra cost. I judged it worth the room and did not try to avoid it.
tsc is clean and the three test files that cover this change pass (test/settings-timing.test.ts, test/palette-tell-gate.test.ts, test/connect-harness.test.ts). I did not run the full suite or scripts/gate.ts; the forge's check runs the full suite on this push.
To try it, open /settings/tokens on the preview at https://lab--10279--forge-trevato-apps.open-platform.sh.
I left out any caching of the visibility lookup; it is one indexed read.
The marketplace lines are the right idea, but four things need fixing in one round:
- Move the visibility lookup out of the page. The raw SQL in
connectCardbelongs in a small core or settings module (e.g.pluginMarketplace(db, config)returning{owner,name}or null). The page should only render. - Add the escaping test the issue's box 3 asks for. The current test only checks the plain
plug/forgecase. Render with an origin carrying"/<and assert the lines are escaped. - Doors: the terminal has no counterpart. Whatever the TUI offers for connecting a harness should show the same marketplace lines under the same public-repo gate.
docs/features/tokens-harness.mddoes not mention the marketplace, and it needs the how-to. - Don't loosen
MAX_STATEMENTSfor/settings/tokensfrom 13 to 15 as a way to pass. Fold the visibility read into an existing read, or cache it, so the budget stays at 13 or goes up by at most 1 with a reason. A page that does more work on every load works against the direction on speed.
Smaller points: the test uses a variable named ada for the plug user, and (app.config as any) should be typed. The 'From a clone' label is only shown when the marketplace shows, which is fine.
The pipeline-first direction applies. This is a feature that is not on the pipeline list, so keep it small.
All four points are done and pushed. tsc and the tests I ran pass, and so do the 12 related test files I ran for pluginsOffered, the plugin lines and /llms.txt; I ran scripts/gate.ts too but its output didn't come through, so its result is unconfirmed. I didn't run the full suite.
- Visibility lookup: the raw SQL is out of the page.
pluginsOfferedinsrc/core/mcp_card.tsnow does a single direct query, and a newmarketplaceLines(origin)there builds the two lines.connectCardonly renders them. - Escaping test: the test in
test/connect-harness.test.tsnow covers a private repository (no lines) and a public one (lines shown). It also sets a hostile public address ("><script>…) and asserts the lines appear escaped and nothing lands raw. The config override is typed (Object.assign),as anyis gone, and theplug/adavariable is gone. - Terminal:
- The terminal had no connect-harness screen. The nearest counterpart is the new-token secret screen (Signed in › m), so that screen now shows the same two lines under the same gate.
- test/tui-token-make.test.ts covers it: no lines with no repository or a private one, lines once it is public.
- docs/features/tokens-harness.md has a how-to section.
- Statement budget:
/settings/tokensgoes from 13 to 14, not 15, with the reason in a comment. The extra statement is the one visibility read, which the page didn't make before. I dropped the separateforge_settingread.
One change to the design: the marketplace repository is now the fixed trevato/forge that /.well-known/mcp.json and /llms.txt already use. It is no longer taken from the forgeRepo setting. That keeps all the printed install lines gated on the same repository, but a forge whose source repository has another name won't get these lines.
Two things to fix in one round.
- Issue box 1 asks for the plugin repository's path to come from the forge's config, not a hard-coded owner. This head hard-codes
trevato/forgethroughPLUGIN_REPO. The builder's note says this was a deliberate step back from theforgeReposetting. The box is not met. Either read the configured source repository (admin setting, elseFORGE_REPO) for the card and for the gate, or get the issue's box changed by a person.
- The terminal's secret screen truncates the marketplace lines. On a narrow terminal the user sees a cut-off command with no copy key for it. The origin there is also built differently from the page's origin. Details are in the line comments.
The rest holds up: the page reuses copyField with no new class, the lines are escaped, the env line is kept, the how-to is in docs/features and not the README, and the statement budget rises by one with a reason.
Settings › Tokens now gives Claude Code two lines that work outside a clone: /plugin marketplace add <origin>/<owner>/<name>.git and /plugin install forge@forge. The clone-only --plugin-dir command and its environment line are still shown. This round takes the plugin repository from the forge's config, keeps one copy of the repository lookup SQL, and fixes the terminal screen.
The repository comes from config. offeredPluginRepo(db, config.forgeRepo) in src/core/mcp_card.ts uses forgeSource: the admin setting, else FORGE_REPO. It returns that owner/name only while the repository is public here. Settings › Tokens, the terminal's new-token screen, /.well-known/mcp.json and /llms.txt all call it, so they always name the same repository. The hard-coded PLUGIN_REPO is gone.
- When the forge names no source, nothing is offered. The
/llms.txtline now says "it names no public source for them", since a missing source and a private one look the same there. - If production does not set
FORGE_REPOand no admin has named a source, the lines will not show there until one is set.
One repository lookup. repoVisibility sits next to getRepo in src/core/repos.ts, and both use one BY_NAME condition, so there is no second copy to drift. The tell-gate test now counts only full SELECT repo.* row reads, not this one-column read.
One origin. src/core/public_origin.ts returns the configured URL, or else the request origin (on the page) or http://host:port (in the terminal), with trailing slashes stripped. When url is configured, the page and the terminal print the same text.
Terminal screen (src/tui/screens/signins.ts). The lines are wrapped whole like the secret, never cut. a copies the marketplace line and i the install line. If the lines don't fit the area's height, one hint ("Plugin lines: a and i copy them.") is shown instead, and the keys still work.
Tests:
test/tui-token-make.test.ts: at 40 columns the lines wrap whole anda/isend them to the clipboard; at 40×12 the lines are skipped butastill copies.test/mcp-card-plugins.test.ts: an admin's setting outranksFORGE_REPOin the card and/llms.txt, and a forge that names no source offers nothing.- The fixtures that relied on the hard-coded name now set
forgeRepo: "trevato/forge".
bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts pass. scripts/fast.ts named 2,035 files because repos.ts changed, so I picked the covering suites instead: tokens/terminal, MCP card, connect, tell-gate, standards, settings timing, ssh-tell, llms, agents page, forge-source, terminal sign-ins and repos. All pass. The forge's full check still has to run on the push.
To try it on the preview: make trevato/forge public, or name a public repository with PATCH /api/v1/admin/settings {"forgeRepo":"owner/name"}. Then open /settings/tokens, or press m under Signed in in the terminal at a narrow width.
🤖 Generated with Claude Code
Settings › Tokens now offers the two plugin marketplace lines (/plugin marketplace add <origin>/<repo>.git and /plugin install forge@forge) beside the existing --plugin-dir clone line. The terminal's new-token screen shows the same lines; a and i copy them.
All the lines come from src/core/mcp_card.ts, which also builds the MCP server card and /llms.txt. They point at the forge's configured source repository: the admin setting, else FORGE_REPO, no longer a hardcoded trevato/forge. They are offered only while that repository is public here, so every printed line works for whoever reads it. The new src/core/public_origin.ts gives the page and the terminal the same origin with no trailing slash, so a line reads the same in both.
Check fix: the anonymous /llms.txt has a 5 KiB budget (5,120 bytes). Locally it sat at 5,116 bytes, and my longer "plugins not offered" wording pushed it over on the check's host. The line is now Harness plugins: not offered here (no public source), about 30 bytes shorter. The expected text in test/standards.test.ts and test/mcp-card-plugins.test.ts changed with it; those tests were not wrong.
Not done: with only a few bytes to spare, the size budget itself is not changed. The next line added to the anonymous text will probably hit it again.
Verified locally: bun x tsc --noEmit and bun scripts/gate.ts pass, as do test/llms-anonymous.test.ts, test/standards.test.ts and test/mcp-card-plugins.test.ts (36 tests).
To try it: on the preview at https://lab--10279--forge-trevato-apps.open-platform.sh, open Settings › Tokens and make a token. If the configured source repository is public, the marketplace lines appear beside the clone line. /llms.txt and /.well-known/mcp.json name the same source; with no public source, /llms.txt prints the shorter not-offered line.
🤖 Generated with Claude Code
All four earlier asks are met. The lookup now lives in core (offeredPluginRepo, repoVisibility), not in the page. The escaping test covers a hostile origin. The terminal secret screen shows the same lines under the same gate, with a how-to in docs/features/tokens-harness.md and README untouched. The statement budget rose by one, with the reason in a comment. The repository comes from forgeSource (admin setting, else FORGE_REPO), and the card, llms.txt, the page and the terminal share one gate. Tests cover the present, private and absent cases, narrow and short terminals, and a setting that outranks the env. Non-blocking: mcp_card.ts uses repo! inside the plugins map; narrowing once would drop the assertions. Non-blocking: the anonymous llms.txt budget has only a few bytes to spare.
The connect card on Settings › Tokens now shows two marketplace lines above the
--plugin-dirline, and a test covers both the present and absent cases.bun testontest/connect-harness.test.ts,test/plugins.test.tsandtest/mcp-card-plugins.test.tspasses, as dotsc --noEmit,scripts/gate.tsandscripts/design-lint.ts. I didn't run the whole suite. I didn't try the page on a running app.What changed
/plugin marketplace add <origin>/<owner>/<name>.gitand/plugin install forge@forge, each a copy field.FORGE_REPO), not a hard-coded owner. The origin is the forge's configured public address, else the request's.--plugin-dircommand follows under a "From a clone" label. TheFORGE_URL/FORGE_TOKENenv line and the OpenCode line behave as before, so a just-minted token still appears once.test/connect-harness.test.tschecks that the marketplace lines are absent while no such repository exists and that only the clone line shows. It then checks that both lines appear with the right origin and path once a publicplug/forgeis set as the source.src/web/pages/account.tsreusescopyField.What I left out
forgeSource's name pattern andcopyFieldescapes the value.PLUGIN_REPOinsrc/core/mcp_card.tsis still hard-coded totrevato/forge, and/llms.txtand/.well-known/mcp.jsonstill read it. Moving them onto the same config setting would be a separate change.plugins/claude-code/README.mdalready documents these commands, so I didn't change it.To try it, set
FORGE_REPO=<owner>/<name>for a public repository that holds the plugin, then open/settings/tokens.Closes #10217