[BUG] Custom theme overrides for permission (and likely other tokens) are silently ignored by the markdown renderer for inline code
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
- Create ~/.claude/themes/test.json:
{ "name": "Test", "base": "dark", "overrides": { "permission": "#FF0000" } } - settings.json:
"theme": "custom:test" - Restart Claude Code and prompt for any response containing inline code.
- 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.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗