Rightshold™ Sign up

Answers · agent safety

How do I make Claude Code reuse my existing components instead of writing new ones?

Short answer: Tell it what exists, give it rules it can check, and enforce the rules outside the prompt. Claude Code reads CLAUDE.md at the start of every session, so put a short component inventory there (name, import path, what each one is for) and concrete rules such as "use Button from @/components/ui/button; never write a raw <button>". Ask it to search the codebase before creating any new component. Claude Code's own docs say CLAUDE.md is context, not enforced configuration, so back the rules with checks that fail: a lint rule that forbids raw elements and duplicate imports, a hook that runs the linter after every edit, and a CI job (lint plus Playwright screenshot tests) that blocks the merge when the agent writes its own version anyway.

Checklist

  1. Write a component inventory into CLAUDE.md (or a file it imports with @path, such as @docs/components.md): one line per shared component with its import path and when to use it. Keep it short; Anthropic recommends keeping each CLAUDE.md under about 200 lines.
  2. Make the rules concrete and checkable: "All buttons use <Button> from @/components/ui/button", "Modals use <Dialog>", "Colors come from the theme tokens in tailwind.config.ts, no hex values in components". Vague rules like "follow our design system" are easy to ignore.
  3. Add a search-first rule: before creating a new component, search src/components for an existing one (by name and by the element it renders) and say which one you're extending; if none fits, explain why before writing a new one.
  4. Scope rules to the files they apply to with .claude/rules/ and a paths: field (for example src/components/**/*.tsx), so they load when Claude touches those files instead of filling every session.
  5. Enforce with lint: eslint-plugin-react's react/forbid-elements can forbid raw <button>, <input> or <dialog> in app code, and ESLint's no-restricted-imports can block importing a second UI library or an old component path. Point the error message at the component to use.
  6. Run the check while Claude works: a Claude Code PostToolUse hook on Edit and Write can run the linter on the changed file and feed the errors back, so the agent fixes them in the same turn.
  7. Fail the pull request in CI: run lint and Playwright visual comparisons (expect(page).toHaveScreenshot()) on key pages, so a hand-rolled copy that looks different from the shared component shows up as a diff.
  8. When Claude still writes a duplicate, add the missed case to CLAUDE.md or the lint config, not just a chat correction, so the next session knows.

Why it writes new components

Instructions vs enforcement

Ask Rightshold (free, no key)

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Claude Code added two new UI packages instead of using our components. Are their licenses OK for our commercial app?”

One-click setup

{
  "tool": "check_rights_batch",
  "arguments": {
    "intended_use": {
      "commercial_use": true,
      "redistribution": true
    },
    "items": [
      {
        "ref": "<new-ui-package>",
        "license": "MIT"
      },
      {
        "ref": "<new-icon-package>",
        "license": "<its SPDX id>"
      }
    ]
  }
}

Rightshold does not read your codebase, review pull requests or enforce coding rules; component reuse is enforced by your CLAUDE.md, lint config, hooks and CI. It checks the licenses of packages an agent adds.

Sources

Related

Not legal advice. Updated 2026-10-29. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'