Browse documentation

Technical documentation / Reference

Runtime theming

Magi-code uses one Opaline semantic theme for Mission Control. Machine output, protocol output, sessions, provider requests, and tool payloads remain unstyled.

Theme IDs and precedence

matrix-green is the embedded Matrix theme. Opaline built-ins use their registered IDs. Custom files are loaded from $MC_HOME/themes/*.toml; their ID is the exact, case-sensitive filename including extension (for example Solarized.toml has ID custom:Solarized.toml).

Resolution order is: explicit temporary --theme ID, saved interface.appearance.theme, then Matrix fallback. An invalid explicit theme is a launch error with exit code 2. An invalid saved theme emits a bounded warning and is not rewritten; runtime falls back to Matrix. A successful /theme save clears a temporary CLI override; cancel and save failure do not.

Settings

{
  "interface": {
    "appearance": { "theme": "matrix-green", "reduced_motion": false },
    "no_color": false
  }
}

Terminal color is disabled when saved interface.no_color is true or NO_COLOR is present (even empty); saved false does not override the environment. Otherwise terminal detection applies: truecolor when COLORTERM is truecolor or 24bit, ANSI-256 when TERM contains 256color, ANSI-16 for a color terminal, and None when color is disabled, stdout is not a TTY, or TERM is dumb. Unicode and animation are separate from color; there is no CLI color override.

During a live run, the prompt border shows a fixed-width ASCII scanner ([>.....]) moving back and forth; it yields space to status and cancel labels in narrow panes. Running tool/subagent cards use dot-orbit indicators. Successful live card indicators and the run-completion status receive a brief bold, underlined accent (650 ms); replay, errors, and cancellation do not trigger it. These cues hide behind modals and are disabled by interface.appearance.reduced_motion. They never change copied transcript text or session history.

Complete custom theme example

Save this self-contained parser-valid file as $MC_HOME/themes/Solarized.toml (the ID is custom:Solarized.toml):

[meta]
name = "Solarized"
author = "example"
variant = "dark"
version = "1.0"
description = "Complete custom theme"

[palette]
background = "#002b36"
panel = "#073642"
code = "#001f27"
highlight = "#0b4f5c"
selection = "#145b68"
primary = "#fdf6e3"
secondary = "#93a1a1"
muted = "#657b83"
dim = "#586e75"
accent = "#2aa198"
accent_secondary = "#268bd2"
accent_tertiary = "#b58900"
accent_deep = "#1b7770"
success = "#859900"
error = "#dc322f"
warning = "#b58900"
info = "#268bd2"

[tokens]
"text.primary" = "primary"
"text.secondary" = "secondary"
"text.muted" = "muted"
"text.dim" = "dim"
"bg.base" = "background"
"bg.panel" = "panel"
"bg.code" = "code"
"bg.highlight" = "highlight"
"bg.selection" = "selection"
"accent.primary" = "accent"
"accent.secondary" = "accent_secondary"
"accent.tertiary" = "accent_tertiary"
"accent.deep" = "accent_deep"
success = "success"
error = "error"
warning = "warning"
info = "info"
"border.focused" = "accent"
"border.unfocused" = "muted"
"code.keyword" = "accent"
"code.function" = "accent_secondary"
"code.string" = "accent_tertiary"
"code.number" = "warning"
"code.comment" = "muted"
"code.type" = "info"
"code.line_number" = "dim"
"magi.surface.background" = "background"
"magi.surface.panel" = "panel"
"magi.surface.panel_alt" = "highlight"
"magi.surface.overlay" = "highlight"
"magi.surface.selection" = "selection"
"magi.surface.code" = "code"
"magi.surface.success" = "highlight"
"magi.surface.pending" = "highlight"
"magi.surface.error" = "highlight"
"magi.text.primary" = "primary"
"magi.text.muted" = "muted"
"magi.text.dim" = "dim"
"magi.text.accent" = "accent"
"magi.text.title" = "accent"
"magi.text.prompt" = "primary"
"magi.text.status" = "secondary"
"magi.text.help" = "secondary"
"magi.text.metadata" = "muted"
"magi.text.command" = "accent_secondary"
"magi.text.command_active" = "accent"
"magi.border.default" = "muted"
"magi.border.active" = "accent"
"magi.border.alternate" = "accent_secondary"
"magi.border.command" = "muted"
"magi.border.command_active" = "accent"
"magi.border.error" = "error"
"magi.status.queued" = "muted"
"magi.status.running" = "warning"
"magi.status.writing" = "warning"
"magi.status.success" = "success"
"magi.status.failed" = "error"
"magi.status.canceled" = "muted"
"magi.status.tool" = "accent_secondary"
"magi.status.subagent" = "accent_tertiary"
"magi.status.assistant" = "accent"
"magi.status.diagnostic" = "info"
"magi.transcript.user" = "accent_secondary"
"magi.transcript.assistant" = "primary"
"magi.transcript.thinking" = "accent_tertiary"
"magi.transcript.tool" = "accent_secondary"
"magi.transcript.session" = "muted"
"magi.transcript.diagnostic" = "info"
"magi.transcript.heading" = "accent"
"magi.transcript.section" = "primary"
"magi.transcript.error_label" = "error"
"magi.transcript.error_body" = "primary"
"magi.diff.inserted" = "success"
"magi.diff.removed" = "error"
"magi.diff.changed" = "warning"
"magi.diff.context" = "primary"
"magi.diff.hunk_header" = "accent_secondary"
"magi.diff.file_header" = "accent"
"magi.diff.metadata" = "muted"
"magi.syntax.plain" = "primary"
"magi.syntax.keyword" = "accent"
"magi.syntax.string" = "accent_tertiary"
"magi.syntax.comment" = "muted"
"magi.syntax.number" = "warning"
"magi.syntax.function" = "accent_secondary"
"magi.syntax.type" = "info"
"magi.syntax.operator" = "accent_secondary"
"magi.syntax.punctuation" = "secondary"
"magi.syntax.code_fence" = "accent"
"magi.syntax.language_label" = "accent_secondary"
"magi.syntax.gutter" = "dim"
"magi.syntax.fallback" = "secondary"

[styles]
keyword = { fg = "accent", bold = true }
line_number = { fg = "dim" }
selected = { fg = "accent", bg = "selection" }
active_selected = { fg = "accent_tertiary", bg = "highlight", bold = true }
focused_border = { fg = "accent" }
unfocused_border = { fg = "muted" }
success_style = { fg = "success" }
error_style = { fg = "error" }
warning_style = { fg = "warning" }
info_style = { fg = "info" }
dimmed = { fg = "dim" }
muted = { fg = "muted" }
inline_code = { fg = "accent_tertiary", bg = "code" }

[gradients]
primary = ["accent", "accent_secondary"]
warm = ["warning", "accent_tertiary"]
success_gradient = ["success", "accent_secondary"]
error_gradient = ["error", "warning"]
aurora = ["accent", "accent_secondary", "accent_tertiary", "info"]
"magi.gradient.fast" = ["accent", "accent_secondary", "accent_tertiary"]

Trust and bounds

Only direct regular files in the themes directory are considered. Symlinks, non-regular entries, non-UTF-8 filenames, and files over 512 KiB are rejected. The scan accepts at most 128 custom files and scans at most 256 directory entries. A source is bounded to 512 KiB, with at most 4096 colors, 1024 styles, 256 gradients, 4096 gradient stops, and token-reference depth 64. Diagnostics are limited to 24 entries, sanitized of control characters, and truncated to 240 characters. Invalid siblings do not prevent valid themes from loading.

Picker behavior

In Mission Control, /theme opens the picker on the current theme’s Dark or Light tab. Tab or Shift-Tab switches tabs and keeps the search text. Type to search within the active tab; Up/Down previews a theme live. Switching tabs previews the first match. If there are no matches, the last preview stays visible and Enter does nothing.

Themes are grouped by their declared [meta].variant ("dark" or "light"), not their names. Custom themes without a variant appear under Dark.

Enter starts saving the selected ID. Esc restores the exact opening appearance snapshot, installed with a fresh monotonic presentation revision. A failed save leaves the preview and picker available for retry; closing or canceling restores the opening state. Each open shows the cached catalog immediately and starts a background refresh; valid refreshes update the cache, and deleted or repaired custom files appear on the next refresh.

Motion and output

interface.no_color disables colors. Mission Control retains style modifiers such as bold where they apply.

Mission Control applies semantic roles to headers, assistant and thinking bodies, tool bodies, metadata, diagnostic levels, Markdown, syntax, and diffs. Colors are lowered to truecolor, 256-color, or 16-color according to the detected depth. Theme data is display-only and never enters sessions, provider requests, tool arguments/results, or protocol output.

The PRD remains Active and pending final acceptance verification; implementation behavior is documented here: docs/prd/0079-full-runtime-theming-custom-themes-and-reduced-motion.md.

Edit this page on GitHub ↗