agents.md holds the instructions, claude.md points at it
opencode discovers only AGENTS.md, Claude Code only CLAUDE.md — so with the content living in CLAUDE.md, every doc here was invisible to opencode. Swaps all five pairs (root, src/apps, src/databases, themes, plugins): AGENTS.md now holds the full text verbatim, CLAUDE.md is a short pointer. docs-check's permission-count regex now reads root AGENTS.md instead of CLAUDE.md; the workspace-level officer-dev/CLAUDE.md check is untouched, out of scope.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# Themes
|
||||
|
||||
Drop a theme in here and it appears in the picker on the next page load. No install step, no rebuild, no
|
||||
restart — a theme is a block of CSS custom properties, and none of that needs compiling.
|
||||
|
||||
**This directory is untracked**, exactly like `plugins/`. Only this file is in the repository. Your themes
|
||||
are yours; the platform's own live in `src/workspaces/theme/css/themes/`.
|
||||
|
||||
---
|
||||
|
||||
## The shape
|
||||
|
||||
```
|
||||
themes/
|
||||
my-theme/
|
||||
theme.css required — the values
|
||||
theme.json required — the name a person reads
|
||||
assets/ optional — a wallpaper, a logo
|
||||
```
|
||||
|
||||
The directory name **is** the theme's id. It is not repeated in the manifest, because an id that can
|
||||
disagree with where its files sit eventually will.
|
||||
|
||||
### `theme.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "My Theme",
|
||||
"family": "My Theme",
|
||||
"dark": true
|
||||
}
|
||||
```
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `name` | required — what the picker shows |
|
||||
| `family` | optional — groups variants together, like `Duck Light` and `Duck Dark`. Defaults to `name` |
|
||||
| `dark` | optional — adds the `.dark` class. Set it for a dark theme; several hundred `dark:` utilities still resolve against it |
|
||||
|
||||
### `theme.css`
|
||||
|
||||
Must target its own directory name, or nothing will happen and it will be baffling:
|
||||
|
||||
```css
|
||||
[data-theme='my-theme'] {
|
||||
--background: #1e1e2e;
|
||||
--foreground: #cdd6f4;
|
||||
/* …the rest */
|
||||
}
|
||||
```
|
||||
|
||||
The server checks this on discovery and reports it rather than letting you wonder.
|
||||
|
||||
---
|
||||
|
||||
## What to put in it
|
||||
|
||||
**Twenty tokens are required.** They are the standard shadcn set, which is what every published palette
|
||||
already ships — Tokyo Night, Catppuccin, Gruvbox, Nord all come in this vocabulary, so porting one is
|
||||
mostly copy-paste.
|
||||
|
||||
```
|
||||
background foreground · card card-foreground · popover popover-foreground
|
||||
primary primary-foreground · secondary secondary-foreground
|
||||
muted muted-foreground · accent accent-foreground
|
||||
destructive destructive-foreground · border input ring · radius
|
||||
```
|
||||
|
||||
**Everything else is derived from those.** Panels, the header, the dock, glass, grid lines, scrollbars —
|
||||
all computed from `card`, `border`, `background` and `foreground`. A palette theme never mentions them.
|
||||
|
||||
**Four more are worth setting**, because the standard set has no notion of them and the defaults are
|
||||
generic: `--success`, `--warning`, `--info`, `--busy`, each with a `-foreground`. `busy` means *running*,
|
||||
not *warning* — it is what a live job wears.
|
||||
|
||||
**Anything else you want to change, you can.** Declaring a variable in your theme beats the derived
|
||||
default, because both land on `<html>` and yours is more specific. That is how a theme gets a *texture*
|
||||
rather than just a palette:
|
||||
|
||||
```css
|
||||
[data-theme='my-theme'] {
|
||||
--panel-bg: rgba(255, 255, 255, 0.08); /* glass instead of a flat card */
|
||||
--panel-blur: 20px;
|
||||
--panel-radius: 0; /* square panels */
|
||||
--page-bg-src: '/themes/my-theme/assets/wallpaper.webp';
|
||||
--logo-src: '/themes/my-theme/assets/logo.svg';
|
||||
}
|
||||
```
|
||||
|
||||
The full list of what you can override is in `src/workspaces/theme/README.md`, and
|
||||
`src/workspaces/theme/css/themes/duck-dark.css` is a worked example of a textured theme.
|
||||
|
||||
**Assets are quoted paths, not `url(...)`.** The bundler resolves `url()` at build time and your files are
|
||||
served at runtime, so a `url()` token would break. The app wraps the path for you.
|
||||
|
||||
---
|
||||
|
||||
## Writing one
|
||||
|
||||
Start from `src/workspaces/theme/css/themes/plain.css` rather than from a Duck theme. Plain is white,
|
||||
black and grey throughout, so every value you change is one you decided about, with nothing inherited from
|
||||
someone else's brand.
|
||||
|
||||
Then: reload the page, open the picker or press `ctrl+shift+space`, and use `j`/`k` to browse. `l` applies
|
||||
the focused theme to the app behind the list, so you can watch your own theme against real screens.
|
||||
|
||||
Editing `theme.css` and reloading is the whole loop. The stylesheet is cached for a minute.
|
||||
|
||||
---
|
||||
|
||||
## Checking your work
|
||||
|
||||
Render the app under **Plain** first if something looks wrong under yours. Anything still coloured under
|
||||
Plain is a component painting itself rather than reading a token — that is a platform bug, not yours, and
|
||||
worth reporting.
|
||||
|
||||
`bun run check:theme` counts hardcoded colours in the platform. It does not check themes, but it is why
|
||||
your theme has a chance of working: the number can only go down.
|
||||
+3
-115
@@ -1,118 +1,6 @@
|
||||
# Themes
|
||||
|
||||
Drop a theme in here and it appears in the picker on the next page load. No install step, no rebuild, no
|
||||
restart — a theme is a block of CSS custom properties, and none of that needs compiling.
|
||||
**The instructions live in [`AGENTS.md`](AGENTS.md). Read it first — this file only points there.**
|
||||
|
||||
**This directory is untracked**, exactly like `plugins/`. Only this file is in the repository. Your themes
|
||||
are yours; the platform's own live in `src/workspaces/theme/css/themes/`.
|
||||
|
||||
---
|
||||
|
||||
## The shape
|
||||
|
||||
```
|
||||
themes/
|
||||
my-theme/
|
||||
theme.css required — the values
|
||||
theme.json required — the name a person reads
|
||||
assets/ optional — a wallpaper, a logo
|
||||
```
|
||||
|
||||
The directory name **is** the theme's id. It is not repeated in the manifest, because an id that can
|
||||
disagree with where its files sit eventually will.
|
||||
|
||||
### `theme.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "My Theme",
|
||||
"family": "My Theme",
|
||||
"dark": true
|
||||
}
|
||||
```
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `name` | required — what the picker shows |
|
||||
| `family` | optional — groups variants together, like `Duck Light` and `Duck Dark`. Defaults to `name` |
|
||||
| `dark` | optional — adds the `.dark` class. Set it for a dark theme; several hundred `dark:` utilities still resolve against it |
|
||||
|
||||
### `theme.css`
|
||||
|
||||
Must target its own directory name, or nothing will happen and it will be baffling:
|
||||
|
||||
```css
|
||||
[data-theme='my-theme'] {
|
||||
--background: #1e1e2e;
|
||||
--foreground: #cdd6f4;
|
||||
/* …the rest */
|
||||
}
|
||||
```
|
||||
|
||||
The server checks this on discovery and reports it rather than letting you wonder.
|
||||
|
||||
---
|
||||
|
||||
## What to put in it
|
||||
|
||||
**Twenty tokens are required.** They are the standard shadcn set, which is what every published palette
|
||||
already ships — Tokyo Night, Catppuccin, Gruvbox, Nord all come in this vocabulary, so porting one is
|
||||
mostly copy-paste.
|
||||
|
||||
```
|
||||
background foreground · card card-foreground · popover popover-foreground
|
||||
primary primary-foreground · secondary secondary-foreground
|
||||
muted muted-foreground · accent accent-foreground
|
||||
destructive destructive-foreground · border input ring · radius
|
||||
```
|
||||
|
||||
**Everything else is derived from those.** Panels, the header, the dock, glass, grid lines, scrollbars —
|
||||
all computed from `card`, `border`, `background` and `foreground`. A palette theme never mentions them.
|
||||
|
||||
**Four more are worth setting**, because the standard set has no notion of them and the defaults are
|
||||
generic: `--success`, `--warning`, `--info`, `--busy`, each with a `-foreground`. `busy` means *running*,
|
||||
not *warning* — it is what a live job wears.
|
||||
|
||||
**Anything else you want to change, you can.** Declaring a variable in your theme beats the derived
|
||||
default, because both land on `<html>` and yours is more specific. That is how a theme gets a *texture*
|
||||
rather than just a palette:
|
||||
|
||||
```css
|
||||
[data-theme='my-theme'] {
|
||||
--panel-bg: rgba(255, 255, 255, 0.08); /* glass instead of a flat card */
|
||||
--panel-blur: 20px;
|
||||
--panel-radius: 0; /* square panels */
|
||||
--page-bg-src: '/themes/my-theme/assets/wallpaper.webp';
|
||||
--logo-src: '/themes/my-theme/assets/logo.svg';
|
||||
}
|
||||
```
|
||||
|
||||
The full list of what you can override is in `src/workspaces/theme/README.md`, and
|
||||
`src/workspaces/theme/css/themes/duck-dark.css` is a worked example of a textured theme.
|
||||
|
||||
**Assets are quoted paths, not `url(...)`.** The bundler resolves `url()` at build time and your files are
|
||||
served at runtime, so a `url()` token would break. The app wraps the path for you.
|
||||
|
||||
---
|
||||
|
||||
## Writing one
|
||||
|
||||
Start from `src/workspaces/theme/css/themes/plain.css` rather than from a Duck theme. Plain is white,
|
||||
black and grey throughout, so every value you change is one you decided about, with nothing inherited from
|
||||
someone else's brand.
|
||||
|
||||
Then: reload the page, open the picker or press `ctrl+shift+space`, and use `j`/`k` to browse. `l` applies
|
||||
the focused theme to the app behind the list, so you can watch your own theme against real screens.
|
||||
|
||||
Editing `theme.css` and reloading is the whole loop. The stylesheet is cached for a minute.
|
||||
|
||||
---
|
||||
|
||||
## Checking your work
|
||||
|
||||
Render the app under **Plain** first if something looks wrong under yours. Anything still coloured under
|
||||
Plain is a component painting itself rather than reading a token — that is a platform bug, not yours, and
|
||||
worth reporting.
|
||||
|
||||
`bun run check:theme` counts hardcoded colours in the platform. It does not check themes, but it is why
|
||||
your theme has a chance of working: the number can only go down.
|
||||
Kept separate so agents that look for `AGENTS.md` by convention find the same guidance as those that
|
||||
look for `CLAUDE.md`, without the two drifting apart.
|
||||
|
||||
Reference in New Issue
Block a user