KKairos/Docs

Authoring themes

A Kairos theme is a JSON manifest declaring 20 semantic tokens. The app compiles it to CSS at install time. No CSS knowledge required — just pick colours, fonts, and radii that match your visual identity.

Manifest format

A complete theme manifest — copy, modify, and paste into the custom theme uploader:

{
  "schemaVersion": 1,
  "id": "my-theme",
  "name": "My Theme",
  "description": "A custom Kairos theme.",
  "author": "Your Name",
  "version": "1.0.0",
  "colorScheme": "dark",
  "preview": {
    "canvas": "#1a1b1e",
    "surface": "#25262b",
    "fg": "#c1c2c5",
    "accent": "#7c3aed"
  },
  "tokens": {
    "--color-canvas": "#1a1b1e",
    "--color-surface": "#25262b",
    "--color-surface-2": "#2c2e33",
    "--color-surface-3": "#373a40",
    "--color-fg": "#c1c2c5",
    "--color-fg-2": "#a6a7ab",
    "--color-fg-3": "#909296",
    "--color-fg-4": "#5c5f66",
    "--color-accent": "#7c3aed",
    "--color-accent-hover": "#6d28d9",
    "--color-line": "#373a40",
    "--color-line-subtle": "#2c2e33",
    "--color-success": "#2f9e44",
    "--color-warning": "#e67700",
    "--color-danger": "#e03131",
    "--font-sans": "system-ui, sans-serif",
    "--font-mono": "ui-monospace, monospace",
    "--radius-sm": "0.25rem",
    "--radius-md": "0.375rem",
    "--radius-lg": "0.5rem"
  }
}

Required tokens

All 20 tokens below are required. A manifest missing any of them will fail validation.

TokenRole
--color-canvasPage background
--color-surfaceCard / panel background
--color-surface-2Slightly elevated surface (input backgrounds)
--color-surface-3Further elevated surface (hover states, badges)
--color-fgPrimary text
--color-fg-2Secondary text
--color-fg-3Muted text (labels, descriptions)
--color-fg-4Placeholder / disabled text
--color-accentPrimary interactive colour (buttons, links, focus rings)
--color-accent-hoverAccent hover state
--color-linePrimary border colour
--color-line-subtleSubtle border (dividers)
--color-successSuccess state
--color-warningWarning state
--color-dangerError / destructive action
--font-sansSans-serif font stack
--font-monoMonospace font stack
--radius-smSmall corner radius
--radius-mdMedium corner radius
--radius-lgLarge corner radius

Optional tokens

You can extend the manifest with any additional CSS custom properties — just add them to the tokens object. Common optional tokens:

  • --color-brandBrand colour (defaults to accent if unset)
  • --color-accent-2Secondary accent colour
  • --color-emeraldEmerald/green accent
  • --color-task-event-bgBackground colour for calendar task events
  • --radius-xlExtra-large corner radius
  • --shadow-sm / --shadow-md / --shadow-lgBox shadow tokens
  • --duration-fast / --duration-normal / --duration-slowAnimation duration tokens

Color value formats

Color token values must be valid CSS color expressions:

  • #1a1b1e
  • rgb(26, 27, 30)
  • rgba(255, 255, 255, 0.08)
  • hsl(240 5% 12%)
  • oklch(15% 0.01 270)
  • oklab(0.15 -0.01 -0.01)

Note: keyword colours like red or transparent are not accepted.

Font imports

To use a web font, add its @import URL to the fontImports array. Only fonts from these sources are allowed:

  • fonts.googleapis.com
  • rsms.me
  • cdn.jsdelivr.net
"fontImports": [
  "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
],
"tokens": {
  "--font-sans": "'Inter', system-ui, sans-serif",
  ...
}

Install your theme

Go to Settings → Appearance → Upload custom theme, paste your manifest JSON, and click "Install". The theme will appear in your pack picker immediately.

To share your theme with the community, submit a PR to the kairos-themes-registry repository.

Safety checks

Every manifest goes through these checks before install:

  • Schema validation — all required fields present and correctly typed
  • Size limit — raw JSON must be under 64KB
  • CSS injection scan — compiled CSS is scanned for @import outside the font allowlist, expression(), behavior:, and javascript: URIs
  • Font allowlist — fontImports must point to approved CDNs
  • ID uniqueness — theme ID must not collide with a built-in pack
  • Token completeness — all 20 required tokens must be present