Skip to content

Design — pinky-streamlit

Update date : 2026-05-31

Architecture decisions, constraints, and trade-offs for pinky-streamlit.


Placement in the suite

pinky-streamlit belongs in this kit because it requires streamlit as a runtime dependency. The rule: any module that imports streamlit at the top level goes here — not in pinky-core. This keeps pinky-core importable in CI, UDFs, and local scripts without pulling in the Streamlit runtime.


CSS architecture — module-scoped

style.css at the package root does Streamlit normalization only (reset, font injection, spacing). Each ui_components/<module>/ owns its own .css file loaded on demand by setup_page().

Why: a page that uses only metric and header should not load chart CSS or table CSS. Loading on demand keeps SiS startup time predictable as the kit grows.


Version pin

streamlit==1.52.2 and plotly==5.24.1 are hard-pinned. The CSS design system uses internal Streamlit CSS selectors that change between versions. Upgrading requires a full visual validation pass before the pin moves.

See docs/reference/generated/api/ for the validated upgrade workflow.


Import alias convention

Module functions are imported with sks_ prefix to avoid shadowing st.* names:

from pinky_streamlit import text as sks_text, metric as sks_metric

Why: Streamlit apps are full of st. calls. An alias makes it immediately clear which components come from the kit vs the Streamlit stdlib.


Local dev mode

get_session() resolves transparently: - SiS: returns the active Snowpark session - Local (PINKY_LOCAL=1): returns a LocalSessionConfig backed by DuckDB

App code never changes — only the resolution layer switches. Local data is populated by pinky dump (from snowflake-tools).


What is deliberately out of scope

  • Pure Python utilities (formatters, validators) → pinky-core
  • Snowpark session management beyond get_session()pinky-snowpark
  • External API calls → pinky-connect
  • Any component that doesn't require streamlit at import time

Container Runtime vs legacy SiS

Two deployment contexts are supported. App code does not change between them — only setup_page() arguments and the presence of config.toml differ.

Legacy SiS (warehouse) Container Runtime (Workspace)
config.toml Not supported Full support
Custom font Base64 data URI (font=DEFAULT_FONT) fontFiles in config.toml (font=None)
primaryColor CSS override (KNOWN LIMITATIONS) Native via config.toml (slider + date picker fixed)
CSS variables setup_page() CSS injection Same — config.toml does not replace CSS variables
External packages Anaconda channel only Any pip package (with EAI)

Container Runtime setup

# 1. Generate .streamlit/config.toml once — commit to project
from pinky_streamlit import PALETTES
print(PALETTES.PYTHIA.to_config_toml(font_files=["static/DMSans.woff2"]))

# 2. Each page
setup_page(session, palette=PALETTES.PYTHIA, font=None)

setup_page() still injects style.css + CSS variables in both modes. config.toml handles what CSS cannot: primaryColor at React level and font loading.

See ADR-0006 for the full rationale.