One token set, many render targets — the SAFE fleet's shared design layer.
Project description
safe-design
One token set, many render targets — the SAFE fleet's shared design layer.
from safe_design import GROVE, Skin
from safe_design.backends import css, textual
textual.color("degraded") # '#ffaf00'
css.resolve("degraded") # '#ffaf00' — same token, same color, by construction
css.emit_skin(GROVE, selector=":root")
Why it exists
The palette was already right. It lived in grove/theme.py, which imported curses
at module scope — so grove/theme_textual.py had to reach across a module boundary
for a private name (from grove.theme import _C) and pay for a terminal library to
read a dict of integers. Nothing outside Grove could import it at all.
So twenty-one other terminal UIs in safe-app-store re-derived it by hand, and the
fleet's own tui-design skill lists "hardcoded colors clashing with user themes"
as pitfall #1 while story-timeline/app.py carries sixty of them.
Tokens do not import render engines. Render engines import tokens.
Layout
| Module | Imports | Role |
|---|---|---|
tokens.py |
stdlib | the palette, borders, glyphs, agent coloring |
color.py |
stdlib | xterm256() — the single index→hex converter |
text.py |
stdlib | cell-width-correct truncate() |
backends/curses_backend.py |
curses |
the only module that imports curses |
backends/textual.py |
stdlib | Textual / Rich colors and markup |
backends/css.py |
stdlib | CSS custom properties, per skin |
Parity is structural
Both the Textual and CSS backends resolve a token through the same xterm256().
They cannot disagree, because neither one converts. test_css_and_textual_agree_on_every_token
exists to catch anyone who breaks that.
Tokens
Base palette lifted verbatim from grove/theme.py: bg, input_bg, border,
primary, secondary, accent, unread, online, idle, busy, healthy,
degraded, down.
SCDS1 §0.4 asks the contract for grant / deny / warn / meter-fill. Three of
those already existed under health names, so they are aliases, not new colors:
grant -> healthy deny -> down warn -> degraded meter_fill -> accent
Aliases resolve at lookup, never at definition. A skin that repaints healthy
moves grant with it. Setting an alias directly is refused:
GROVE.derive("bbs", grant=10)
# ValueError: skin 'bbs' overrides alias tokens: ['grant'].
# Override the canonical token instead (grant -> healthy).
Skins
A skin fills the contract; it never extends it. Every token resolves in every skin,
so a consumer can rely on --color-warn existing forever.
bbs = GROVE.derive("bbs", bg=0, primary=15, accent=14, healthy=10, down=9)
css.emit_skin(bbs) # [data-skin="bbs"] { --color-bg: #000000; ... }
GROVE.ascii() # same colors, +-| chrome, for TERM=dumb
Agent identity colors
Hash-derived and stable. The same agent gets the same color forever, and no one assigns it.
textual.agent_color("willow") # '#87ff87'
textual.agent_color("hanuman") # '#5fffff'
Tests
python3 -m pytest tests/ -q
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file safe_design-0.0.1.tar.gz.
File metadata
- Download URL: safe_design-0.0.1.tar.gz
- Upload date:
- Size: 11.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfdd4f49089237b9dc46c80e00ee4115202af62a8e54285ab4e0ca9d437dc44a
|
|
| MD5 |
539e4b29c08b28b9ad37afcc71d44b66
|
|
| BLAKE2b-256 |
fb23338ad76e5cc285092880aaa23d6cf20da7044122aad2f6be82cc3d5ad720
|
Provenance
The following attestation bundles were made for safe_design-0.0.1.tar.gz:
Publisher:
release.yml on rudi193-cmd/safe-design
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_design-0.0.1.tar.gz -
Subject digest:
dfdd4f49089237b9dc46c80e00ee4115202af62a8e54285ab4e0ca9d437dc44a - Sigstore transparency entry: 2123278274
- Sigstore integration time:
-
Permalink:
rudi193-cmd/safe-design@457cb7ec69aa2afb4c7acdd8fde8acbeaeb37f10 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/rudi193-cmd
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@457cb7ec69aa2afb4c7acdd8fde8acbeaeb37f10 -
Trigger Event:
push
-
Statement type:
File details
Details for the file safe_design-0.0.1-py3-none-any.whl.
File metadata
- Download URL: safe_design-0.0.1-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa1172d6277671a7369bc720e7cbce59e94bfb745517ff5dbd168ed162fa3292
|
|
| MD5 |
af63be51c6a34a9024946d0147c6f15c
|
|
| BLAKE2b-256 |
ac70a121b60a33bca04048568e98af04cf57b643482867fd1fe195f376157ee3
|
Provenance
The following attestation bundles were made for safe_design-0.0.1-py3-none-any.whl:
Publisher:
release.yml on rudi193-cmd/safe-design
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_design-0.0.1-py3-none-any.whl -
Subject digest:
aa1172d6277671a7369bc720e7cbce59e94bfb745517ff5dbd168ed162fa3292 - Sigstore transparency entry: 2123278365
- Sigstore integration time:
-
Permalink:
rudi193-cmd/safe-design@457cb7ec69aa2afb4c7acdd8fde8acbeaeb37f10 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/rudi193-cmd
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@457cb7ec69aa2afb4c7acdd8fde8acbeaeb37f10 -
Trigger Event:
push
-
Statement type: