[BUG] Custom theme overrides for permission (and likely other tokens) are silently ignored by the markdown renderer for inline code

Resolved 💬 2 comments Opened May 22, 2026 by collinm-zillow Closed May 26, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Version:

Setting "permission": "#5DE4c7" (or any value) in a custom theme's overrides has no visible effect on inline code (code) rendering in assistant messages. The base dark theme's permission color (rgb(177,185,249) / #B1B9F9) is used instead. Other overrides in the same theme (e.g. clawd_body, userMessageBackground, success) do apply correctly, confirming the theme is loading.

What Should Happen?

Claude should respect overrides in custom themes.

Error Messages/Logs

N/A

Steps to Reproduce

  1. Create ~/.claude/themes/test.json: { "name": "Test", "base": "dark", "overrides": { "permission": "#FF0000" } }
  2. settings.json: "theme": "custom:test"
  3. Restart Claude Code and prompt for any response containing inline code.
  4. Inline code renders in #B1B9F9 (base dark), not #FF0000.

Claude Model

None

Is this a regression?

No, this has not worked

Last Working Version

_No response_

Claude Code Version

Claude Code v2.1.148 (macOS arm64)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

I had Claude inspect itself, including this in case it's helpful. Passes the sniff test, but of course this is from the minified bundle so I'm not sure what the source looks like.

Root cause (from bundle inspection)

In the minified bundle, the markdown renderer's codespan case is:

case "codespan": return vq("permission", _)(H.text);

where _ is the theme name (e.g. "custom:test"), not the merged theme object.

vq resolves the color via Lg(themeName)[tokenName]:

function vq(H, _, q="foreground") {
  return (K) => {
    if (!H) return K;
    if (H.startsWith("rgb(") || H.startsWith("#") || H.startsWith("ansi256(") || H.startsWith("ansi:"))
      return FAH(K, H, q);
    return FAH(K, Lg(_)[H], q);  // <-- bypasses user overrides
  };
}

Lg only knows built-in themes; everything else falls through to default:

function Lg(H) {
  switch (H) {
    case "light":              return yc1;
    case "light-ansi":         return hc1;
    case "dark-ansi":          return Ec1;
    case "light-daltonized":   return Sc1;
    case "dark-daltonized":    return Ic1;
    default:                   return Cc1;  // base dark theme
  }
}

So vq("permission", "custom:test") returns Cc1.permission — the base dark theme's value — and the
user's overrides (applied elsewhere via a FS9(base, overrides) merge) are never consulted.

Scope

Any token resolved through vq(name, themeName) likely has the same bug. From the bundle, vq() is called
with these tokens:

claude, error, fastMode, inactive, permission, promptBorder, success, suggestion, text, warning

Most users won't notice because tokens like text and claude are also applied via direct Ink/JSX color
props that do use the merged theme. But anywhere markdown is rendered into a string (codespan, em,
strong, headings, etc. — all routed through this switch), the user override is dropped.

Suggested fix

Either:

  • (a) Have vq() accept and use the merged theme object instead of looking up by name, or
  • (b) Have Lg() resolve "custom:*" theme names by loading and merging the user's theme.

(a) is probably cleaner — pass the already-merged theme down to the renderer rather than re-resolving
by name at each call site.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗