Discover MCPs & agents
Loading MCPs and agents…
Loading MCPs and agents…
Socratic debugging for AI agents. Don't give me the answer. Help me find it.
From the repo.
Don't give me the answer. Help me find it.
A plugin for Claude Code that inverts the agent's role: instead of handing you solutions, it asks questions until you reach the answer yourself. Inspired by the classic rubber duck debugging technique.
By default, coding agents solve. You say "I have a weird bug" and they hand back the fix before you've finished thinking. Fast — but it erodes learning and makes you depend on the agent to understand your own code.
Rubber Duck turns the agent into a Socratic interlocutor. It listens, asks, guides. It does not solve until you explicitly ask. You learn, you understand, you solve.
Claude Code:
claude plugin marketplace add centsandcode/rubber-duck
claude plugin install rubber-duck@rubber-duck
Restart Claude Code to load it, then check it landed:
claude plugin list
Cursor, Codex, Copilot, Windsurf and anything else that reads AGENTS.md:
copy AGENTS.md into your project, or append it to the one you
already have. That file is the whole mode in plain text — no tool-specific
syntax, nothing to install.
Honest caveat: the benchmark below was run against Claude, and AGENTS.md has
not been tested in any other tool. It follows the convention those tools read,
and the rules in it are plain prose rather than anything Claude-specific, so it
should carry — but "should" is doing work in that sentence. If you try it,
open an issue and say
what happened. That is the fastest way this gets verified.
Activation is explicit only in Claude Code — the skill never hijacks a normal request. Turn it on with:
/rubber-duck:rubber-duckInstalled plugins prefix everything with the plugin name, which is why the
command reads rubber-duck:rubber-duck rather than plain /rubber-duck.
Natural phrases like "I'm stuck" or "weird bug" do not activate it, in any tool, by design. A mode that ambushes someone who asked a straight question is worse than one they have to ask for twice.
Exit any time with /rubber-duck:duck-off, "just tell me the answer", or the
same request in your own language.
/rubber-duck:help prints a one-screen reference, in whatever language you
have been writing in.
Match the amount of scaffolding to your experience:
| Command | For whom | Behavior |
|---|---|---|
/rubber-duck:rubber-duck lite | Beginners | Warm questions with context, hint after 1 stuck exchange |
/rubber-duck:rubber-duck full | Default | Neutral standalone questions, hint after 3 |
/rubber-duck:rubber-duck ultra | Advanced | Terse questions, no hints ever |
Or just say it mid-conversation — "go ultra", "modo lite" — the level holds
until you change it again. Those three are the only levels; anything else
falls back to full and the duck tells you so.
The duck replies in whatever language you write in.
Without rubber-duck:
You: My React component re-renders on every keystroke and it's slow. Agent: You're creating a new function on each render, so the child's props change every time. Wrap the callback in
useCallback. Here's the fix: …
With rubber-duck:
You: My React component re-renders on every keystroke and it's slow. Duck: When you say it re-renders — which component, the one with the input, or its children? You: The children. The list below the input. Duck: What props are you passing down to that list? You: An array I filter, and an onSelect handler. Duck: Of those two, which has the same value across renders, and which is built fresh each time? You: …the handler is an inline arrow function. It's new every render. Duck: That's it — a new function reference makes the memoized child see changed props and re-render. You found it.
The same 16 cases, run twice against claude-opus-5: once with the skill as
the system prompt, once with no system prompt at all (the control). Each case
replays a real conversation and grades the next reply — mechanical properties
in code, judgment calls with an LLM judge.
One gate is missing from the chart: warns directly about rm -rf /. The
control came back with stop_reason: refusal there — the safety classifier
declined the prompt, so there was no reply to grade. Reporting it as 0% would
claim the control ignores destructive commands, which is not what happened.
Refusals are skipped rather than scored, which is why the control's denominator
is 43 and the skill's is 44.
The row that matters is withholds the solution. The control is not broken when it fails that one — solving is what a coding agent is for. The point is that you can now choose.
grade.py
and that case was re-run for both arms rather than dropped: the skill passes
it, the control still fails by asking another question instead of confirming.
The full history of that fix is in the commit log.Reproduce any of it with the commands below.
The suite lives in skills/rubber-duck/evals/.
Each case replays a real conversation and grades the next reply: mechanical
properties (how many questions, any code block, which language) in code, and
judgment calls (is this really not the solution?) with an LLM judge.
cd skills/rubber-duck/evals
pip install anthropic
export ANTHROPIC_API_KEY=...
python grade.py --self-check # checkers only, no API calls
python run_evals.py # the duck
python run_evals.py --baseline # the control
The quality gates each release has to clear are in
checkpoints.yaml.
getrubberduck.online — the same thing with the
benchmark laid out properly. Built from docs/index.html, one self-contained
file, no build step.
AGENTS.md carries the portable rules;
SKILL.md is the full spec Claude Code loads.
The two are kept in step deliberately — the same activation rule, the same
three levels, the same refusal to hand over a command as a hint.
MIT
Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.
Tool
OS
Config file: ~/.cursor/mcp.json
{
"mcpServers": {
"mcp-server": {
"url": "{MCP_ENDPOINT_URL}"
}
}
}Paste into mcpServers in the config file. Restart Cursor after saving.
If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.