streamlit
Use when building a personal or team dashboard with Streamlit — KPI tiles with day-over-day change, multipage apps, data delivered as dated JSON files in a git repository, caching, a private deploymen
SKILL.mdskills/tech/streamlit/SKILL.md
GitHubStreamlit dashboards
Default: one repository holding both the app and its data (one JSON file per day per source), a thin app.py entry point, pages in pages/ or st.navigation, data access through cached functions, tests with streamlit.testing.v1.AppTest.
Data flow that needs no server
- Producers (scheduled jobs elsewhere) write
data/<source>/<YYYY-MM-DD>.jsonand push to the main branch. - The app lists the files, loads them with
@st.cache_data(ttl=600), and shows the latest day plus trends. - A
?date=YYYY-MM-DDquery parameter (st.query_params) shows any past day.
Write only what the dashboard needs into the data files (counts, dates, categories); the repository becomes the audit log.
Layout
- KPI row:
st.columnswithst.metric(label, value, delta)— delta versus the previous day. - Below: charts of the last 30 days, then tables with links to sources.
- A one-line description under each page title saying what the page answers.
Deployment (Community Cloud)
- Choose the Python version in the app's advanced settings to match local development.
- Keep the app private and invite viewers explicitly; check that a signed-out browser is redirected to login.
- Secrets go in the app's secrets settings, read with
st.secrets, never in the repository. - Notifications elsewhere (chat messages) can then carry only a short line and the dashboard URL instead of long reports.
Entry point and imports
- Point the deployment at a small
app.py. If the configured entry is a package__init__.py, Streamlit runs it as a script — guard heavy code withif __name__ == "__main__":or change the entry. - After a push, the platform may reload
app.pywhile helper modules stay cached insys.modules; a new page calling a new function from an old module raisesAttributeError. Avoidimportlib.reloadtricks (they can fail withImportErrorunder the runner); instead clear your package's modules fromsys.modulesat the top of the entry script before importing, or restart the app.
Testing
from streamlit.testing.v1 import AppTest
def test_overview_renders():
at = AppTest.from_file("app.py").run(timeout=30)
assert not at.exception
assert at.metric[0].label == "Merged PRs"
Also test the cloud-like entry path (run the same entry file in a subprocess) so import-order bugs show up locally.
Verification loop
pytestwith AppTest: no exceptions on every page, with real sample data files.streamlit run app.pyand click through each page.- After deploy, open the URL signed out (must require login) and signed in (pages render).
Pitfalls
- Rerun model: the whole script reruns on every interaction; keep expensive work in cached functions.
- Mutable cached objects:
st.cache_datareturns copies;st.cache_resourcereturns shared objects — do not mutate them per user. - Large tables slow the browser; aggregate first.
- Time zones: dates in file names are in the producer's zone; label them.