Skip to content

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-official or another marketplace with one of Anthropic's official names (listed on /docs/plugins/security). claude-community is 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:

VariableSet byCaveat
CLAUDECODE=1Every Claude Code version, in Bash and PowerShell tool commands and hook commandsIDE 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=1v2.1.172 and later, only in subprocesses Claude Code starts itselfPrecise, 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.

AttributeAllowed valueMeaning
v1Protocol version
typepluginKind of hint
valuename@marketplaceThe 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. value names 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_TRACK or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC set, 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:

ChoiceEffect
Yes, installInstalls at user scope
NoDismisses; this plugin will not be offered again
No, and don't show plugin installation hints againTurns off hint prompts for all plugins for that user
No answer within 30 secondsCounted as No

Because the plugin description is shown, make sure the one in your marketplace entry reads well as a standalone pitch.