Skip to Content

Streamlit Dashboards

TL;DR

Skills that store data (SQLite, JSON logs) can include a Streamlit dashboard for visualization. The dashboard uses synchronous sqlite3 + pandas for read-only access, avoiding conflicts with the skill’s async runtime.

When to add a dashboard

Add a dashboard when your skill accumulates data over time — audit logs, scan results, monitoring metrics. The dashboard provides a visual interface for exploring that data.

Directory structure

my-skill/ ├── skill/ ├── src/my_skill/ ├── dashboard/ │ ├── app.py # Streamlit entry point │ ├── db_reader.py # Sync data access │ ├── charts.py # Reusable chart components │ └── requirements.txt # streamlit, pandas └── data/ # Runtime data (gitignored) └── my_skill.db

The async problem

Skills use async libraries (httpx, Tortoise ORM) for their runtime. Streamlit is synchronous and runs in a separate process. Sharing an async database connection is not possible.

Solution: use sqlite3 + pandas for read-only access in the dashboard. The skill writes to SQLite via Tortoise ORM; the dashboard reads via sqlite3.

Dashboard entry point

dashboard/app.py:

import streamlit as st import pandas as pd from db_reader import load_data st.set_page_config(page_title="My Skill Dashboard", layout="wide") # Guard: stop if no data df = load_data() if df.empty: st.info("No data yet. Run the skill first.") st.stop() # Sidebar filters with st.sidebar: status = st.selectbox("Status", ["all"] + df["status"].unique().tolist()) if status != "all": df = df[df["status"] == status] # Main content st.title("My Skill Results") st.dataframe(df, use_container_width=True)

st.set_page_config() must be the first Streamlit call. Place it before any other st.* function.

Database reader

dashboard/db_reader.py:

import sqlite3 from pathlib import Path import pandas as pd DB_PATH = Path(__file__).resolve().parent.parent / "data" / "my_skill.db" def load_data() -> pd.DataFrame: if not DB_PATH.exists(): return pd.DataFrame() conn = sqlite3.connect(str(DB_PATH)) df = pd.read_sql_query("SELECT * FROM results ORDER BY created_at DESC", conn) conn.close() return df

Derive DB_PATH from __file__ — never hardcode absolute paths.

Dashboard dependencies

dashboard/requirements.txt:

streamlit>=1.40.0 pandas>=2.0.0

Running the dashboard

pip install -r dashboard/requirements.txt streamlit run dashboard/app.py

Opens at http://localhost:8501. Use --server.port 8502 for a custom port.

Auto-refresh

For monitoring dashboards that need live updates:

import time placeholder = st.empty() while True: df = load_data() with placeholder.container(): st.dataframe(df, use_container_width=True) time.sleep(30) st.rerun()

Entry point in pyproject.toml

Optionally add a script entry point for convenience:

[project.scripts] my-skill = "my_skill._skill:main" my-skill-dashboard = "streamlit:run dashboard/app.py"
Last updated on