Recommend your plugin from your CLI
Have your CLI or SDK print a claude-code-hint line so Claude Code users are offered your official-marketplace plugin, and know when the prompt shows.
If you ship a command-line tool and also publish a Claude Code plugin for it, you can get the two to meet. When Claude runs your CLI through its Bash or PowerShell tool, your CLI prints a one-line <claude-code-hint /> tag to stderr. Claude Code strips that line before Claude sees the output and shows the user a one-time offer to install your plugin.
Note: This only works for plugins listed in
claude-plugins-officialor another marketplace with one of Anthropic's official names (listed on /docs/plugins/security).claude-communityis not one of them. Getting listed is covered in /docs/plugins/publish.
Detect that you are running under Claude Code
Only print the hint when Claude Code launched you. Two environment variables tell you:
| Variable | Set by | Caveat |
|---|---|---|
CLAUDECODE=1 | Every Claude Code version, in Bash and PowerShell tool commands and hook commands | IDE extensions also set it in their integrated terminals, so a human running your CLI in VS Code's terminal will see the hint line |
CLAUDE_CODE_CHILD_SESSION=1 | v2.1.172 and later, only in subprocesses Claude Code starts itself | Precise, but misses users on older versions |
Gate on CLAUDECODE for the widest reach, or on CLAUDE_CODE_CHILD_SESSION if you can require v2.1.172+. See /docs/env-vars.
Emit the hint
Suppose your tool is shipit and your plugin is listed as shipit in the official marketplace. In a Node CLI, at startup:
// src/cli/claude-hint.js
export function maybeHintClaudePlugin() {
const underClaude =
process.env.CLAUDE_CODE_CHILD_SESSION === '1' || Boolean(process.env.CLAUDECODE);
if (!underClaude) return;
process.stderr.write('<claude-code-hint v="1" type="plugin" value="shipit@claude-plugins-official" />\n');
}
The same idea in Python:
import os, sys
def maybe_hint_claude_plugin() -> None:
if os.environ.get("CLAUDE_CODE_CHILD_SESSION") or os.environ.get("CLAUDECODE"):
sys.stderr.write('<claude-code-hint v="1" type="plugin" value="shipit@claude-plugins-official" />\n')
And in a shell wrapper:
if [ -n "${CLAUDE_CODE_CHILD_SESSION:-}${CLAUDECODE:-}" ]; then
echo '<claude-code-hint v="1" type="plugin" value="shipit@claude-plugins-official" />' >&2
fi
Print it on every run. Claude Code handles de-duplication, prompting at most once per plugin.
Test the emitter
CLAUDECODE=1 shipit status 2>&1 >/dev/null | grep claude-code-hint # should match
shipit status 2>&1 >/dev/null | grep claude-code-hint # should print nothing
Tag format
The tag must sit on a line by itself. A tag in the middle of other text is ignored.
| Attribute | Allowed value | Meaning |
|---|---|---|
v | 1 | Protocol version |
type | plugin | Kind of hint |
value | name@marketplace | The plugin to recommend |
All three are required. Values can be double-quoted or bare; bare values cannot contain whitespace. Claude Code strips the line from tool output even if v or type is something it does not recognise, so future versions will not leak tags into Claude's context.
When users actually see a prompt
Only interactive terminal sessions show the prompt. In claude -p, subagent runs and hook command output, the tag is silently removed. Every one of these must also be true:
- Official and installable.
valuenames a plugin found in Claude Code's local copy of an official marketplace, not already installed, and not blocked by policy. - Analytics on. Sessions with analytics off never prompt: for example with
DISABLE_TELEMETRY,DO_NOT_TRACKorCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICset, or on a third-party provider such as Amazon Bedrock where telemetry is off automatically (see /docs/data-usage). - Within frequency limits. One prompt per session; one prompt ever per plugin, whatever the answer; none at all once 100 plugins have been prompted for on that machine.
- Not opted out. The user has not picked the "don't show again" option.
- Local and attended. The workspace is local, not cloud or remote, and the session is not unattended. Sessions started with
--cloud, sessions serving Remote Control and agent-team teammates never prompt.
In practice this means most of your users will see it once, the first time Claude runs your tool in a normal terminal session.
What the user sees
A Plugin recommendation dialog appears, saying that your command (it shows the first word of the shell command Claude ran, so users can spot a mismatch) suggests installing a plugin, with the plugin name, marketplace and description. The choices are:
| Choice | Effect |
|---|---|
| Yes, install | Installs at user scope |
| No | Dismisses; this plugin will not be offered again |
| No, and don't show plugin installation hints again | Turns off hint prompts for all plugins for that user |
| No answer within 30 seconds | Counted as No |
Because the plugin description is shown, make sure the one in your marketplace entry reads well as a standalone pitch.