Automatic light/dark theme selection?

Resolved 💬 49 comments Opened Jul 4, 2025 by djsavvy Closed May 31, 2026

Like many others, I have my terminal switch automatically between light and dark mode, following the system theme.

However, I have to manually adjust my Claude Code theme every time. Sometimes I forget until I notice blank spots in the output (i.e. unreadable text).

Is it possible for the theme to switch automatically?

View original on GitHub ↗

49 Comments

cgaaf · 1 year ago

Yes I agree with this. Even when the theme is changed sometimes I have to exit claude code and restart which is not ideal

drichardson · 12 months ago

Or have a mode will claude uses standard terminal colors so that people using terminal color schemes (like solarized dark and light) will just work out of the box

sam3k · 11 months ago

This is much needed as non highlighted syntax becomes unreadable when theme mode does not match

<img width="315" height="161" alt="Image" src="https://github.com/user-attachments/assets/139ca3e2-3393-455d-8f49-36495f2c2b6e" />

phaberest · 11 months ago

Totally agree with this, Claude Code is almost unreadable for me when the terminal is in light mode 🤕

joeldrotleff · 11 months ago

Very very much want this. And it's bad because if you try to switch while in CC it doesn't work, you have to exit and restart CC for it to even take effect.

rpadaki · 9 months ago

fwiw, here's what i do on my vimrc and similar on my powerline:

if system('defaults read -g AppleInterfaceStyle') == "Dark\n"
  set background=dark
  let ayucolor="dark"
else
  set background=light
  let ayucolor="light"
endif  
function powerline_precmd() {
  local __ERRCODE=$?
  local __THEME="system-$(defaults read -g AppleInterfaceStyle >/dev/null 2>/dev/null && echo "dark" || echo "light")"
 ...

it's kinda jankety and i haven't thought about it in a long time, but if it proves too hard to support all OS/terminal combinations first-party, I wonder if something like a precmd hook which can run some logic and update config accordingly on-the-fly would work? And just leave it up to users to configure appropriately for their system and themes

antonioacg · 9 months ago

It has become a major issue now with Claude 2.0.

<img width="406" height="198" alt="Image" src="https://github.com/user-attachments/assets/d896a2fb-8b75-45c0-a79e-3e37c91f0422" />

ace-express · 9 months ago
It has become a major issue now with Claude 2.0. <img alt="Image" width="406" height="198" src="https://private-user-images.githubusercontent.com/8991621/495663587-d896a2fb-8b75-45c0-a79e-3e37c91f0422.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTkzMzA5MDAsIm5iZiI6MTc1OTMzMDYwMCwicGF0aCI6Ii84OTkxNjIxLzQ5NTY2MzU4Ny1kODk2YTJmYi04Yjc1LTQ1YzAtYTc5ZS0zZTM3YzkxZjA0MjIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MTAwMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTEwMDFUMTQ1NjQwWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWQ1MjAzMjJhNjBmZDU0YjQ2MjVmZTMxN2Y3ZjNiZTc1YmRkZjA4MWYyMDU4MjlhMDk4MzVjZGY2NTE0NGNmZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.MFYpp4Ntj-Z5HsFrlyhWxT6gqzREjO7HJy7LjmmgpKM">

me too, on maoos terminal app

goshatch · 9 months ago

Another vote for this.

NightMachinery · 9 months ago

Is there at least a way to force the theme with --theme or CLAUDE_THEME?

humberaquino · 9 months ago

+1 for this 🙏

dvic · 9 months ago

Yeah this would be so nice, in case of technical uncertainty how to approach this, helix recently merged a pr for this: https://github.com/helix-editor/helix/pull/14356 (that might be a good start)

asw28 · 8 months ago

Same issue here

<img width="201" height="118" alt="Image" src="https://github.com/user-attachments/assets/4192222d-c17a-4609-b3a0-b52aced4ddae" />

durandom · 7 months ago

my current workaround: https://github.com/durandom/dotfiles/commit/29c6a04db06fd1f09a4924541abbeb469ebfdc25

  • a script to set the theme
  • hook into wezterms auth theme switching

obviously heavily bound to macos and wezterm.

github-actions[bot] · 6 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

zerowidth · 6 months ago

This is still the most noticeable friction point I have with claude code.

broccolism · 6 months ago

Any progress here?

charleseff · 5 months ago

+1 for this.

1) Attempting to set theme via external scripts (including hooks) doesn't persist because CC manages ~/.claude.json internally and overwrites external changes
2) CC's light theme shows invisible text when using a dark terminal theme. Vice versa also true. This absolutely requires that I either a) switch manually with /theme when my OS/terminal switches theme, or b) don't have my OS/terminal auto-switch themes. Both of these options are unsatisfactory.

elhenro · 5 months ago
This is still the most noticeable friction point I have with claude code.

same here, and the bug exists for a long time now.

It is annoying to work around by manually specifying different scheme colors every time.

So, claude code does not yet support dark mode? :D

dulev · 5 months ago

+1 for this

advdrone · 5 months ago

Really annoying this hasn't been implemented yet, the solution is simple: add an "auto" selection to the /theme command. Then, allow users to specify which theme is used for light vs dark.

chriswydra · 4 months ago

Another vote for this. For implementation, OSC 11 (query terminal background color) is probably the most reliable cross-platform approach. The terminal responds with the current background RGB values, and you can derive light/dark from the luminance. This works regardless of OS — it queries the terminal directly, so it handles macOS, Linux, remote SSH sessions, etc.

Helix recently merged this approach: https://github.com/helix-editor/helix/pull/14356

Other tools that use it: bat, delta, vim (via &background).

For mid-session switching, Claude Code could also listen for SIGWINCH (which terminals like Ghostty, iTerm2, and WezTerm send when the theme changes) and re-query OSC 11 at that point.

barrettruth · 4 months ago

Yep, +1 and OSC is the way to do this. Neovim uses it as well.

bricksdont · 4 months ago

+1 would love to have this (I have dark mode in IDE and light mode in terminals otherwise)

rutefig · 4 months ago

+1 I have to always manually switch between dark and light with my terminal switching automatically for day and night shifts

MartinCura · 4 months ago

Please pretty please, just put an agent on it 🙏🏼 half the time i can't see parts of the code because i can't even change the theme if it's already working on something (and if i send /theme it thinks its LLM input!)

drichardson · 4 months ago

If Claude code was open source a community member would have fixed by now (probably using Claude code to to it).

Issues like this are why opencode is probably gonna win long term.

pepelsbey · 4 months ago

I would really like to see this implemented 🥲

<img width="736" height="924" alt="Image" src="https://github.com/user-attachments/assets/7457a18d-f340-43cc-baf8-06b44f70734b" />

tkgalk · 4 months ago

It's wild to me, that such a basic thing is not done in 2026 out-of-the box. Claude Code uses React to render a CLI. Maybe the tech stack is too complicated for an if statement to switch between two colour palettes? Why isn't Claude just following whatever term colours I have in the shell? Just grab my "green", "foreground" et cetera and go.

lancewillett · 4 months ago

Adding another +1. Ghostty already handles this natively with theme = light:Light Theme,dark:Dark Theme in config – it watches system appearance and switches instantly. Claude Code is one of the few terminal tools I use that requires manual /theme toggling.

A "theme": "auto" setting in ~/.claude.json that listens for AppleInterfaceThemeChangedNotification on macOS (and the equivalent on Linux) would close this gap. The community has built LaunchAgent workarounds like claude-theme-sync, but they can only update the config file – they can't affect a running session, which is the whole point.

bn-l · 4 months ago
Any progress here?

I don't think we have the technology to automatically switch the theme. It's too complicated and there are too many moving pieces. I think it's hard enough running the game engine that powers claude code at 60 (!) fps.

bn-l · 4 months ago
> > Any progress here? > > > I don't think we have the technology to automatically switch the theme. It's too complicated and there are too many moving pieces. I think it's hard enough running the game engine that powers claude code at 60 (!) fps. It might be easier than you think. https://contour-terminal.org/vt-extensions/color-palette-update-notifications/

Wow! This is mind blowing! I must be dreaming. Honestly it's hard to believe... it's just that hard of a problem. Actually I don't believe. No. No this is too hard of a problem to solve before AGI.

tby321 · 4 months ago

All the technology is readily available, and it probably wouldn't take Claude even long to implement it themselves.
https://contour-terminal.org/vt-extensions/color-palette-update-notifications/

epaynter · 3 months ago

Would love to see this. I switch between light and dark throughout the day and manually running /theme every time is annoying. An auto/system option would be great.

philoserf · 3 months ago

+1. macOS exposes this via AppleInterfaceStyle, and terminals like Ghostty already support dark:X,light:Y theme declarations. Claude Code is the only terminal tool I use that requires manual /theme toggling when the OS switches appearance.

See also #11813 and #16769, both closed as duplicates without linking here or to #1302.

yurukusa · 3 months ago

A Notification start hook can detect the system theme and adjust:

IS_DARK=false
if command -v defaults >/dev/null 2>&1; then
    STYLE=$(defaults read -g AppleInterfaceStyle 2>/dev/null)
    [ "$STYLE" = "Dark" ] && IS_DARK=true
fi
if command -v gsettings >/dev/null 2>&1; then
    SCHEME=$(gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null)
    echo "$SCHEME" | grep -q 'dark' && IS_DARK=true
fi
if [ -f ~/.config/kdeglobals ]; then
    grep -q 'ColorScheme.*[Dd]ark' ~/.config/kdeglobals && IS_DARK=true
fi
if grep -qi microsoft /proc/version 2>/dev/null; then
    REG_VAL=$(reg.exe query 'HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' /v AppsUseLightTheme 2>/dev/null | grep -o '0x[0-9]*')
    [ "$REG_VAL" = "0x0" ] && IS_DARK=true
fi
if [ "$IS_DARK" = true ]; then
    echo "🌙 Dark mode detected" >&2
else
    echo "☀️ Light mode detected" >&2
fi
exit 0

Note: the hook can detect the system theme, but Claude Code doesn't currently expose a theme-switching API. The detection result can be used by statusLine scripts or terminal profile switchers (e.g., tmux set-option -g status-bg).

saagarjha · 3 months ago

I had Claude write a self-contained patcher that hooks rendering:

import { execSync } from "node:child_process";
import { register } from "node:module";

// Cache system appearance with a TTL so we don't shell out on every render.
let cachedAppearance = null;
let cacheTime = 0;
const TTL = 60000;

function systemIsDark() {
  const now = Date.now();
  if (now - cacheTime < TTL) return cachedAppearance === "dark";
  cacheTime = now;
  try {
    const out = execSync(
      `osascript -e 'tell application "System Events" to get dark mode of appearance preferences'`,
      { stdio: "pipe", encoding: "utf-8" }
    ).trim();
    cachedAppearance = out === "true" ? "dark" : "light";
  } catch {
    cachedAppearance = "dark";
  }
  return cachedAppearance === "dark";
}

function remapTheme(name) {
  const wantDark = systemIsDark();
  const isDark = name.includes("dark");
  if (isDark === wantDark) return name;
  return isDark ? name.replace("dark", "light") : name.replace("light", "dark");
}

globalThis.__ccRemapTheme = remapTheme;

register("data:text/javascript," + encodeURIComponent(`
export async function load(url, context, nextLoad) {
  const result = await nextLoad(url, context);
  if (!url.endsWith("/cli.js") || !url.includes("claude-code")) return result;

  let source =
    typeof result.source === "string"
      ? result.source
      : Buffer.from(result.source).toString("utf-8");

  let patched = 0;

  const getThemeRe =
    /(function \\w+\\()(\\w+)(\\)\\{switch\\(\\2\\)\\{case"light":)/;
  const m1 = source.match(getThemeRe);
  if (m1) {
    source = source.replace(
      m1[0],
      m1[1] + m1[2] + m1[3].replace(
        "switch(" + m1[2] + ")",
        m1[2] + "=globalThis.__ccRemapTheme?.(" + m1[2] + ")??" + m1[2] + ";switch(" + m1[2] + ")"
      )
    );
    patched++;
  }

  const buildThemeRe =
    /(function \\w+\\()(\\w+)(,\\w+\\)\\{)(let \\w+=\\2\\.includes\\("dark"\\))/;
  const m2 = source.match(buildThemeRe);
  if (m2) {
    source = source.replace(
      m2[0],
      m2[1] + m2[2] + m2[3] + m2[2] + "=globalThis.__ccRemapTheme?.(" + m2[2] + ")??" + m2[2] + ";" + m2[4]
    );
    patched++;
  }

  if (patched === 0) {
    console.error("[auto-theme] Could not find any functions to patch");
  } else {
    console.error("[auto-theme] Patched " + patched + " function(s)");
  }

  return { ...result, source, shortCircuit: true };
}
`));

You can use it by setting NODE_OPTIONS="--import /path/to/this.js" before running claude. Obviously you should change the command it runs (currently AppleScript) to get the system theme.

zhiyuan-zhang0206 · 3 months ago

I really need this. Imagine paying over 300 dollars for a software without auto dark mode. My optometrist would love this though

kylesnowschwartz · 3 months ago

I'm building a CLI tool (the-themer) that switches themes across terminal apps in one command — Ghostty, bat, delta, fzf, starship, neovim, etc. For Claude Code, the only option is writing "theme": "dark" or "theme": "light" directly to ~/.claude.json via sjson.

This works for new sessions but doesn't live-update running ones. Every other app in the chain picks up the change immediately (Ghostty watches its config, neovim gets a Themery call, fzf reloads on next prompt). Claude Code is the one holdout that requires a restart.

An env var (CLAUDE_THEME), a CLI flag (--theme), or just reliably watching ~/.claude.json for external changes would all unblock this. Any of those would let theme-switching tools treat Claude Code like every other terminal app.

ryanolson-dandy · 3 months ago

They shipped it

petrovicigor · 3 months ago
They shipped it

They did, but you can't choose which themes it's switching, so if you like ANSI colors light/dark themes (like I do), you are out of luck.

domas-ksd · 3 months ago

It does nothing in Alacritty

matheik · 2 months ago

Filed a focused follow-up for the accessibility gap left open by v2.1.111's auto theme: #50179. Current auto doesn't compose with the daltonized or ANSI palettes, so colorblind users still can't get ambient light switching.

romacv · 2 months ago

Finally 👏
<img width="1042" height="708" alt="Image" src="https://github.com/user-attachments/assets/327c8d9f-0370-44dc-9f40-d3d76eba4eb5" />

joshkaplan · 2 months ago

does not seem to work inside tmux

Weniverse-git · 2 months ago

For anyone using WezTerm on macOS, I built a workaround that achieves real-time dark/light auto-switching (not just at startup):

https://gist.github.com/Weniverse-git/f63794a5cc41dec2d1114da828769d08

How it works

  1. WezTerm's window-config-reloaded event fires when macOS appearance changes.
  2. A small Lua handler overwrites a custom theme file (~/.claude/themes/<name>.json) with {"base":"dark"} or {"base":"light"}.
  3. Claude Code's file watcher detects the change and hot-reloads the theme in already-running sessions.

End result: toggle macOS appearance → Claude Code colors switch instantly, in sync with the terminal.

Requires

  • Claude Code v2.1.118+ (custom theme support)
  • WezTerm
  • macOS (Linux/Windows users would need to adapt the appearance detection)

Caveats

  • This is a workaround using the existing custom-theme + file-watcher mechanisms; an official auto-theme that re-detects on appearance change would still be much cleaner.
  • Other terminals (iTerm2, Ghostty, etc.) don't expose appearance events to Lua/scripts as cleanly, so this approach doesn't directly port.

Hope this helps someone until a native solution lands.

djsavvy · 1 month ago

Wow, this issue has been quite an adventure! It seems to be solved for me; thanks to the Anthropic team for adding support. Closing this issue feels like the end of an era :D