Formats diverge
TOML, YAML, KDL, Lua, JSON, properties, packaged extensions—one semantic palette has to survive every syntax.
MATERIAL DESIGN 3 · LOCAL CLI · 19 REGISTERED TARGETS
Theme Manager turns a seed color or included theme definition into coordinated light and dark files for terminals, editors, shell tools, Git UIs, and developer agents—then applies them through the same adapter contract.
tman generate -c "#6750A4" -V "Tonal spot" #CFBDFE#CBC2DB#EFB8C8#FFB4AB#141218#E6E0E9$ tman generate -c "#6750A4" -V "Tonal spot"
Generating color scheme (Tonal spot)
✓ Writing Neovim colorschemes
✓ Running registered generators
material_darkmaterial_dark.luamaterial.vsixmaterial_dark_lazygit_theme.ymlmaterial_dark.tomlmaterial_dark.jsonGenerate and apply support varies by adapter.
ONE PIPELINE · REAL OUTPUT
Theme Manager resolves one semantic light/dark model, writes Neovim colorschemes, then runs each registered generator independently. One adapter failure does not stop the others.
tman generate -c "#6750A4" -V "Tonal spot" material_darkmaterial_dark.tomlmaterial_dark.jsonCapability truth: 18 targets generate; 18 targets apply.
TOML, YAML, KDL, Lua, JSON, properties, packaged extensions—one semantic palette has to survive every syntax.
The same adapter defines generate write and select read paths, enforced by contract tests.
Pointers, reload hooks, installed-package discovery, and environment gates belong to each target.
.lua.toml.json.jarStart with a seed or a repository theme. Material roles expand into light and dark surfaces, accents, context colors, and ANSI palettes.
Each adapter owns its generated filename, destination, environment gate, and reload behavior. Generate and select cannot silently disagree about the source path.
Choose a seed color and one of the available Material variants, or load an included definition. Theme Manager resolves light and dark semantic colors, writes Neovim, then lets each generator format its own output.
Read the contractContent · Expressive · Fidelity · Fruit salad · Monochrome · Neutral · Rainbow · Tonal spot · Vibrant Start the local web UI to inspect a generated light/dark scheme without writing theme files. The interactive selector also renders a Ghostty-palette preview before you confirm a mode.
Read the contract/api/preview → light + dark Select a theme and mode once. Applicable adapters copy or replace their live target, create target-specific extras, and run reload hooks sequentially; skipped and failed adapters do not erase successful ones.
Read the contractselect → 18 applicable adapters A ThemeGenerator owns the generation path and the application contract. Add the adapter once to ALL_ADAPTERS; derived flow lists and contract tests enforce its declared capabilities.
Read the contractThemeGenerator → ALL_ADAPTERS → tests tman -c "#6750A4" -V "Tonal spot"Pass a hex seed and variant, pick a random, favorite, or last color, or name an included theme.
tman serve → PreviewOpen tman serve and request Preview. The route builds both schemes in memory and does not write theme files.
tman generate -c "#6750A4" -V "Tonal spot"Write both modes for Neovim and every generation-capable adapter. Adapter failures are isolated.
tman select --theme material --darkSelect a theme and mode. Each applicable adapter updates its live target and hook; VS Code remains package-only.
Complete dark-mode output from three generation-capable adapters. Each excerpt is produced in memory by the same formatter used by the CLI.
material_dark# Generated Material dark Theme for Ghostty
# Generated by theme-generator
# Format: key = RRGGBB (hex colors without #)
# Place this file in ~/.config/ghostty/themes/
# Basic colors
background = 141218
foreground = e6e0e9
cursor-color = cfbdfe
selection-background = 49454e
# Selection foreground usually contrasts with selection-background
selection-foreground = e6e0e9
# Color palette (ANSI Colors)
# Normal colors (0-7)
palette = 0=948f99
palette = 1=ffb4ab
palette = 2=6fe063
palette = 3=ffee5f
palette = 4=cfbdfe
palette = 5=efb8c8
palette = 6=cbc2db
palette = 7=e6e0e9
# Bright colors (8-15)
palette = 8=aea6b6
palette = 9=ffcbc0
palette = 10=84fb76
palette = 11=ffff70
palette = 12=ead5ff
palette = 13=ffcee2
palette = 14=e6dafa
palette = 15=fff8ff
# Optional: Define extended colors (16-255) if needed by specific applications
# palette = 16=RRGGBB # Example: map tertiaryContainer if available
# palette = 17=RRGGBB # Example: map secondaryContainer if available
# ...
material_dark.toml# -----------------------------------------------------------------------------
# Material Theme (dark)
# Generated by theme-generator for Alacritty
# -----------------------------------------------------------------------------
# Import this file in your main alacritty.toml:
# import = ["~/.config/alacritty/material_themes/material_dark.toml"] # Adjust path as needed
[window]
blur = false
opacity = 1
[colors.primary]
background = '#141218'
foreground = '#e6e0e9'
# Dim/Bright foreground variants (optional, uncomment if needed)
# dim_foreground = '...'
# bright_foreground = '...'
[colors.cursor]
cursor = '#cfbdfe'
text = '#141218' # Use background color for cursor text for contrast
[colors.vi_mode_cursor] # Optional: Same styling for Vi mode cursor
cursor = '#cfbdfe'
text = '#141218'
[colors.selection]
background = '#4d3d75' # Use primaryContainer or fallback
text = '#e9ddff' # Use onPrimaryContainer or fallback
# Normal colors (ANSI colors 0-7)
[colors.normal]
black = '#e6e0e9'
red = '#ffb4ab'
green = '#6fe063'
yellow = '#ffee5f'
blue = '#cfbdfe'
magenta = '#efb8c8'
cyan = '#cbc2db'
white = '#e6e0e9'
# Bright colors (ANSI colors 8-15)
[colors.bright]
black = '#e6e0e9'
red = '#ffcbc0'
green = '#84fb76'
yellow = '#ffff70'
blue = '#ead5ff'
magenta = '#ffcee2'
cyan = '#e6dafa'
white = '#e6e0e9'
# Dim colors (optional, uncomment and define if needed)
# [colors.dim]
# black = '...'
# ...
# white = '...'
# Indexed Colors (Example: using warmAccent and error)
# Allows defining colors beyond the standard 16 ANSI colors.
[[colors.indexed_colors]]
index = 16
color = '#f5d2ff'
[[colors.indexed_colors]]
index = 17
color = '#ffb4ab'
# You can add more indexed colors (up to 255) if needed by applications.
material_dark.json{
"name": "material dark",
"colors": {
"accent": "#cfbdfe",
"border": "#948f99",
"borderAccent": "#cfbdfe",
"borderMuted": "#49454e",
"success": "#6fe063",
"error": "#ffb4ab",
"warning": "#ffee5f",
"muted": "#cac4cf",
"dim": "#948f99",
"text": "#e6e0e9",
"thinkingText": "#cac4cf",
"selectedBg": "#4d3d75",
"userMessageBg": "#211f25",
"customMessageBg": "#2b292f",
"toolPendingBg": "#211f25",
"toolSuccessBg": "#2b292f",
"toolErrorBg": "#93000a",
"statusLineBg": "#1d1b21",
"userMessageText": "#e6e0e9",
"customMessageText": "#e6e0e9",
"customMessageLabel": "#cfbdfe",
"toolTitle": "#e6e0e9",
"toolOutput": "#cac4cf",
"mdHeading": "#cfbdfe",
"mdLink": "#cbc2db",
"mdLinkUrl": "#cac4cf",
"mdCode": "#efb8c8",
"mdCodeBlock": "#e6e0e9",
"mdCodeBlockBorder": "#49454e",
"mdQuote": "#cac4cf",
"mdQuoteBorder": "#948f99",
"mdHr": "#49454e",
"mdListBullet": "#cfbdfe",
"toolDiffAdded": "#6fe063",
"toolDiffRemoved": "#ffb4ab",
"toolDiffContext": "#cac4cf",
"syntaxComment": "#948f99",
"syntaxKeyword": "#cbc2db",
"syntaxFunction": "#cfbdfe",
"syntaxVariable": "#e6e0e9",
"syntaxString": "#efb8c8",
"syntaxNumber": "#633b48",
"syntaxType": "#cbc2db",
"syntaxOperator": "#cfbdfe",
"syntaxPunctuation": "#e6e0e9",
"thinkingOff": "#948f99",
"thinkingMinimal": "#49454e",
"thinkingLow": "#cfbdfe",
"thinkingMedium": "#cbc2db",
"thinkingHigh": "#efb8c8",
"thinkingXhigh": "#ffb4ab",
"bashMode": "#cbc2db",
"pythonMode": "#efb8c8",
"statusLineSep": "#948f99",
"statusLineModel": "#efb8c8",
"statusLinePath": "#cfbdfe",
"statusLineGitClean": "#6fe063",
"statusLineGitDirty": "#ffee5f",
"statusLineContext": "#cbc2db",
"statusLineSpend": "#cfbdfe",
"statusLineStaged": "#6fe063",
"statusLineDirty": "#ffee5f",
"statusLineUntracked": "#ffb4ab",
"statusLineOutput": "#e6e0e9",
"statusLineCost": "#633b48",
"statusLineSubagents": "#cbc2db"
}
}Capability labels and counts come from the same canonical registry used by generate and select. Categories are an editorial grouping for browsing.
19 targets shown
material_dark_lazygit_theme.yml.ymlmaterial_dark.kdl.kdlmaterial_dark.properties.propertiesmaterial_darkpackagematerial_dark.yml.ymlEmits reference YAML; convert it to EZA_COLORS before use.
View adapter sourcematerial_dark.kdl.kdlmaterial_dark.gitconfig.gitconfigmaterial_dark.toml.tomlmaterial_dark.sh.shmaterial_dark.toml.tomlmaterial_dark.toml.tomlmaterial.jar.jarPackages both modes in one JAR and discovers installed IDEs when applying.
View adapter sourcematerial_dark.toml.tomlmaterial_dark.xml.xmlTermux-only; apply uses a privileged, non-atomic su copy and preserves or assigns file permissions.
View adapter sourcematerial_dark.lua.luaThe registry adapter applies current.lua; the separate highlight engine generates its colorschemes.
View adapter sourcematerial_dark.conf.confmaterial.vsix.vsixGenerate-only VSIX package; select does not live-apply it.
View adapter sourcematerial_dark.json.jsonSelect validates and atomically replaces tman.json, then signals interactive TUI processes with SIGUSR2.
View adapter sourcematerial_dark.json.jsonSelect validates and atomically replaces tman.json, then touches it for the built-in file watcher.
View adapter sourceNo targets match those filters.
Theme source, semantic colors, output writer, generated file, live destination—each layer has one job. The registry orders the lifecycle; contract tests keep generate and select aligned.
Each specimen is loaded through the repository theme loader and expanded into the same semantic model. The colors are not retouched for marketing.
A workspace looks coherent only when its tools agree on more than one hex value. Theme Manager gives shared roles to surfaces, text, accents, context, and terminal ANSI colors, then translates those roles into each application’s format.
The same adapter contract owns generation and application, so maintaining support means changing one lifecycle instead of reconciling parallel lists.
The CLI, local web UI, TUI, source, and adapter registry stay inspectable. When your setup needs another target, the extension point is code—not another pile of copied themes.
Start with a hex seed and one of 9 Material Design 3 variants, or choose one of 168 included theme definitions. Both paths resolve to the same light/dark semantic color model.
19 targets are registered. 18 participate in generate, 18 participate in select, and 17 do both. VS Code is generate-only; Neovim’s registry adapter is apply-only because its colorschemes come from the separate highlight engine.
Yes. Generate writes managed theme files and updates ~/.tg.json. Select copies or replaces individual live targets and may run reload hooks. Theme Manager uses atomic writes for managed files and many adapter destinations; MiXplorer’s privileged su copy is an explicit non-atomic exception. Successful targets are not rolled back when another adapter fails, and the current CLI has no backup or dry-run file-diff flag.
Yes: start tman serve and use Preview. Its preview route builds the light and dark schemes in memory. The terminal selector also shows a Ghostty-palette preview, but confirming a selection applies it. Generate and Select are write operations.
Not with the current CLI. Generate visits every generation-capable target; Select visits every apply-capable target and lets each adapter skip environments where it does not apply.
Generation writes both modes. Select applies the mode you choose, and Theme Manager remembers the most recent light and dark selections independently.
Implement the ThemeGenerator or ThemeAdapter contract, add one instance to ALL_ADAPTERS, and extend the path, registry, output, and hook tests described in the integration architecture guide.
Node.js 22 or newer and the source-install steps below. The --pick flow also requires pastel. Adapters gate Termux-only and outside-Termux targets at apply time; consult the integration guide for each tool’s configuration and reload behavior.
Clone the repository, install with pnpm, and generate the default Material theme—or read the workflow first.
git clone https://github.com/Ajaymamtora/theme-manager.git theme-manager
cd theme-manager
pnpm install
pnpm add --global .