axiom-coding-agent-setup 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.agents/skills/agent-browser/SKILL.md +55 -0
  2. package/.agents/skills/developing-with-streamlit/SKILL.md +220 -0
  3. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-chat-ui/SKILL.md +195 -0
  4. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/SKILL.md +233 -0
  5. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/packaged-components.md +212 -0
  6. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/state-sync.md +149 -0
  7. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/theme-css-variables.md +243 -0
  8. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/troubleshooting.md +121 -0
  9. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-dashboards/SKILL.md +147 -0
  10. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-multipage-apps/SKILL.md +218 -0
  11. package/.agents/skills/developing-with-streamlit/skills/choosing-streamlit-selection-widgets/SKILL.md +139 -0
  12. package/.agents/skills/developing-with-streamlit/skills/connecting-streamlit-to-snowflake/SKILL.md +188 -0
  13. package/.agents/skills/developing-with-streamlit/skills/creating-streamlit-themes/SKILL.md +486 -0
  14. package/.agents/skills/developing-with-streamlit/skills/displaying-streamlit-data/SKILL.md +199 -0
  15. package/.agents/skills/developing-with-streamlit/skills/improving-streamlit-design/SKILL.md +191 -0
  16. package/.agents/skills/developing-with-streamlit/skills/optimizing-streamlit-performance/SKILL.md +323 -0
  17. package/.agents/skills/developing-with-streamlit/skills/organizing-streamlit-code/SKILL.md +91 -0
  18. package/.agents/skills/developing-with-streamlit/skills/setting-up-streamlit-environment/SKILL.md +128 -0
  19. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-cli/SKILL.md +165 -0
  20. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-custom-components/SKILL.md +170 -0
  21. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-layouts/SKILL.md +229 -0
  22. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-markdown/SKILL.md +207 -0
  23. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-session-state/SKILL.md +144 -0
  24. package/.agents/skills/developing-with-streamlit/templates/.gitattributes +3 -0
  25. package/.agents/skills/developing-with-streamlit/templates/apps/README.md +188 -0
  26. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/pyproject.toml +12 -0
  27. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/streamlit_app.py +365 -0
  28. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/pyproject.toml +12 -0
  29. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/streamlit_app.py +461 -0
  30. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/.streamlit/secrets.toml.example +20 -0
  31. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/pyproject.toml +11 -0
  32. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/snowflake.yml +18 -0
  33. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/streamlit_app.py +527 -0
  34. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/pyproject.toml +12 -0
  35. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/streamlit_app.py +307 -0
  36. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/pyproject.toml +12 -0
  37. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/streamlit_app.py +426 -0
  38. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/.streamlit/secrets.toml.example +20 -0
  39. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/pyproject.toml +11 -0
  40. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/snowflake.yml +18 -0
  41. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/streamlit_app.py +463 -0
  42. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/pyproject.toml +12 -0
  43. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/streamlit_app.py +252 -0
  44. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/pyproject.toml +12 -0
  45. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/streamlit_app.py +342 -0
  46. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/.streamlit/secrets.toml.example +20 -0
  47. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/pyproject.toml +11 -0
  48. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/snowflake.yml +18 -0
  49. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/streamlit_app.py +384 -0
  50. package/.agents/skills/developing-with-streamlit/templates/themes/README.md +128 -0
  51. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/dracula.toml +39 -0
  52. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/github.toml +37 -0
  53. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/minimal.toml +39 -0
  54. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/nord.toml +39 -0
  55. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/snowflake.toml +42 -0
  56. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/solarized-light.toml +38 -0
  57. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/spotify.toml +34 -0
  58. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/stripe.toml +35 -0
  59. package/.agents/skills/developing-with-streamlit/templates/themes/_shared/streamlit_app.py +336 -0
  60. package/.agents/skills/developing-with-streamlit/templates/themes/_templates/pyproject.toml.tmpl +12 -0
  61. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/.streamlit/config.toml +39 -0
  62. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/pyproject.toml +10 -0
  63. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/streamlit_app.py +337 -0
  64. package/.agents/skills/developing-with-streamlit/templates/themes/github/.streamlit/config.toml +37 -0
  65. package/.agents/skills/developing-with-streamlit/templates/themes/github/pyproject.toml +10 -0
  66. package/.agents/skills/developing-with-streamlit/templates/themes/github/streamlit_app.py +337 -0
  67. package/.agents/skills/developing-with-streamlit/templates/themes/manage.py +332 -0
  68. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/.streamlit/config.toml +39 -0
  69. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/pyproject.toml +10 -0
  70. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/streamlit_app.py +337 -0
  71. package/.agents/skills/developing-with-streamlit/templates/themes/nord/.streamlit/config.toml +39 -0
  72. package/.agents/skills/developing-with-streamlit/templates/themes/nord/pyproject.toml +10 -0
  73. package/.agents/skills/developing-with-streamlit/templates/themes/nord/streamlit_app.py +337 -0
  74. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/.streamlit/config.toml +42 -0
  75. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/pyproject.toml +10 -0
  76. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/streamlit_app.py +337 -0
  77. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/.streamlit/config.toml +38 -0
  78. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/pyproject.toml +10 -0
  79. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/streamlit_app.py +337 -0
  80. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/.streamlit/config.toml +34 -0
  81. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/pyproject.toml +10 -0
  82. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/streamlit_app.py +337 -0
  83. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/.streamlit/config.toml +35 -0
  84. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/pyproject.toml +10 -0
  85. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/streamlit_app.py +337 -0
  86. package/.agents/skills/fastapi/SKILL.md +436 -0
  87. package/.agents/skills/fastapi/references/dependencies.md +142 -0
  88. package/.agents/skills/fastapi/references/other-tools.md +76 -0
  89. package/.agents/skills/fastapi/references/streaming.md +105 -0
  90. package/.agents/skills/frontend-design/LICENSE.txt +177 -0
  91. package/.agents/skills/frontend-design/SKILL.md +42 -0
  92. package/.agents/skills/gradio/SKILL.md +84 -0
  93. package/.agents/skills/gradio/references/api-signatures.md +115 -0
  94. package/.agents/skills/gradio/references/event-listeners.md +130 -0
  95. package/.agents/skills/gradio/references/examples.md +613 -0
  96. package/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  97. package/.agents/skills/ui-ux-pro-max/data +1 -0
  98. package/.agents/skills/ui-ux-pro-max/scripts +1 -0
  99. package/.env.axiom +8 -0
  100. package/AGENTS.md +2 -1
  101. package/README.md +19 -3
  102. package/bin/cli.js +11 -1
  103. package/opencode.json +7 -4
  104. package/package.json +1 -1
  105. package/skills-lock.json +36 -0
  106. package/.agents/skills/n8n-patterns/SKILL.md +0 -272
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: improving-streamlit-design
3
+ description: Improving visual design in Streamlit apps. Use when polishing apps with icons, badges, spacing, or text styling. Covers Material icons, badge syntax, divider alternatives, and text casing conventions.
4
+ license: Apache-2.0
5
+ ---
6
+
7
+ # Streamlit visual design
8
+
9
+ Small touches that make apps feel polished.
10
+
11
+ **Related skills:** Visual design works hand-in-hand with other skills:
12
+ - `choosing-streamlit-selection-widgets` → Choosing the right widget (segmented control, pills, toggle)
13
+ - `displaying-streamlit-data` → Column config, sparklines, bordered metrics
14
+ - `using-streamlit-layouts` → Containers, alignment, dashboard cards
15
+
16
+ ## Page config
17
+
18
+ Set browser tab title, icon, and layout. Place this at the top of your script to avoid visual blinking:
19
+
20
+ ```python
21
+ st.set_page_config(
22
+ page_title="My Dashboard",
23
+ page_icon=":material/analytics:",
24
+ layout="wide", # Use "wide" for dashboards with lots of data
25
+ )
26
+ ```
27
+
28
+ **Layout options:**
29
+ - `layout="centered"` (default) → Best for most apps, content is constrained to a readable width
30
+ - `layout="wide"` → Full-width, good for dashboards and data-heavy apps
31
+
32
+ ## App logo
33
+
34
+ Add a logo to the sidebar/header:
35
+
36
+ ```python
37
+ st.logo("logo.png")
38
+ ```
39
+
40
+ ## Icons over emojis
41
+
42
+ Use Material icons for a cleaner, more professional look.
43
+
44
+ ```python
45
+ # GOOD: Material icons
46
+ st.markdown(":material/settings:")
47
+ st.markdown(":material/calendar_today:")
48
+ st.markdown(":material/dashboard:")
49
+ st.markdown(":material/person:")
50
+
51
+ # SPARINGLY: Emojis for special occasions
52
+ st.markdown("Celebration! 🎉")
53
+ ```
54
+
55
+ Format: `:material/icon_name:`
56
+
57
+ Find icons: https://fonts.google.com/icons
58
+
59
+ **Popular icons by category:**
60
+
61
+ | Category | Icons |
62
+ |----------|-------|
63
+ | Navigation | `home`, `arrow_back`, `menu`, `settings`, `search` |
64
+ | Actions | `send`, `play_arrow`, `refresh`, `download`, `upload`, `save`, `delete`, `edit` |
65
+ | Status | `check_circle`, `error`, `warning`, `info`, `pending` |
66
+ | Data | `table_chart`, `bar_chart`, `analytics`, `query_stats`, `database` |
67
+ | Content | `chat`, `code`, `description`, `article`, `folder` |
68
+ | UI | `visibility`, `build`, `tune`, `filter_list` |
69
+
70
+ ## Badges for status
71
+
72
+ For standalone badges:
73
+ ```python
74
+ st.badge("Active", icon=":material/check:", color="green")
75
+ st.badge("Pending", icon=":material/schedule:", color="orange")
76
+ st.badge("Deprecated", color="red")
77
+ ```
78
+
79
+ For inline badges in text:
80
+ ```python
81
+ st.markdown("""
82
+ :green-badge[Active] :orange-badge[Pending] :red-badge[Deprecated] :blue-badge[New]
83
+ """)
84
+ ```
85
+
86
+ Avoid the old verbose syntax:
87
+ ```python
88
+ # OLD (still works but cluttered)
89
+ st.markdown(":orange-background[:orange[Pending]]")
90
+ ```
91
+
92
+ ## Spacing: remove dividers
93
+
94
+ Dividers (`st.divider()` or `---`) look heavy. Just remove them—Streamlit's default spacing is usually enough.
95
+
96
+ ```python
97
+ # BAD
98
+ st.header("Section 1")
99
+ st.write("Content")
100
+ st.divider() # Too heavy
101
+ st.header("Section 2")
102
+
103
+ # GOOD
104
+ st.header("Section 1")
105
+ st.write("Content")
106
+ st.header("Section 2")
107
+ ```
108
+
109
+ If you genuinely need spacing:
110
+ ```python
111
+ st.space("small") # Small gap
112
+ st.space("medium") # Medium gap
113
+ st.space("large") # Large gap
114
+ st.space(50) # Custom pixels for fine-tuning
115
+ ```
116
+
117
+ **Don't** systematically replace dividers with `st.space()`—it can look weird too.
118
+
119
+ ## Sentence casing
120
+
121
+ Use sentence casing for titles and labels. Title Case Feels Shouty.
122
+
123
+ ```python
124
+ # GOOD
125
+ st.title("Upload your data")
126
+ st.selectbox("Select a region", options)
127
+ st.button("Save changes")
128
+
129
+ # BAD
130
+ st.title("Upload Your Data")
131
+ st.selectbox("Select A Region", options)
132
+ ```
133
+
134
+ ## Caption over info
135
+
136
+ `st.info()` is too heavy for simple informational text.
137
+
138
+ ```python
139
+ # GOOD: Lighter
140
+ st.caption("Data last updated 5 minutes ago")
141
+
142
+ # BAD: Too heavy
143
+ st.info("Data last updated 5 minutes ago")
144
+ ```
145
+
146
+ **When to use what:**
147
+ - `st.caption` → Simple info, metadata, timestamps
148
+ - `st.info` → Important instructions
149
+ - `st.warning` → Caution, potential issues
150
+ - `st.error` → Errors that block progress
151
+ - `st.success` → Confirmation of action
152
+ - `st.toast` → Lightweight confirmation that auto-dismisses
153
+
154
+ ## Text alignment
155
+
156
+ Use `text_alignment` for text elements:
157
+
158
+ ```python
159
+ st.title("Centered title", text_alignment="center")
160
+ st.write("Right aligned", text_alignment="right")
161
+ st.caption("Justified text", text_alignment="justify")
162
+ ```
163
+
164
+ Options: `"left"` (default), `"center"`, `"right"`, `"justify"`
165
+
166
+ **Note:** `horizontal_alignment` on containers positions elements but also sets their `text_alignment`. If you need different text alignment within a horizontally-aligned container, override `text_alignment` on the text element itself.
167
+
168
+ ## Icons in callouts and expanders
169
+
170
+ Material icons can make callouts and expanders look nicer:
171
+
172
+ ```python
173
+ st.info("Processing complete", icon=":material/check_circle:")
174
+ st.warning("Rate limit approaching", icon=":material/warning:")
175
+ st.error("Connection failed", icon=":material/error:")
176
+ st.success("Saved!", icon=":material/thumb_up:")
177
+
178
+ with st.expander("Settings", icon=":material/settings:"):
179
+ st.write("Configure your preferences")
180
+ ```
181
+
182
+ Other elements like `st.button` and `st.tabs` also support icons—worth considering when it adds clarity.
183
+
184
+ ## References
185
+
186
+ - [st.set_page_config](https://docs.streamlit.io/develop/api-reference/configuration/st.set_page_config)
187
+ - [st.logo](https://docs.streamlit.io/develop/api-reference/media/st.logo)
188
+ - [st.badge](https://docs.streamlit.io/develop/api-reference/text/st.badge)
189
+ - [st.space](https://docs.streamlit.io/develop/api-reference/layout/st.space)
190
+ - [st.markdown](https://docs.streamlit.io/develop/api-reference/text/st.markdown)
191
+ - [st.toast](https://docs.streamlit.io/develop/api-reference/status/st.toast)
@@ -0,0 +1,323 @@
1
+ ---
2
+ name: optimizing-streamlit-performance
3
+ description: Optimizing Streamlit app performance. Use when apps are slow, rerunning too often, or loading heavy content. Covers caching, fragments, and static vs dynamic widget choices.
4
+ license: Apache-2.0
5
+ ---
6
+
7
+ # Streamlit performance
8
+
9
+ Performance is the biggest win. Without caching and fragments, your app reruns everything on every interaction.
10
+
11
+ ## Caching
12
+
13
+ ### @st.cache_data for data
14
+
15
+ Use for any function that loads or computes data.
16
+
17
+ ```python
18
+ # BAD: Recomputes on every rerun
19
+ def load_data(path):
20
+ return pd.read_csv(path)
21
+
22
+ # GOOD: Cached
23
+ @st.cache_data
24
+ def load_data(path):
25
+ return pd.read_csv(path)
26
+ ```
27
+
28
+ ### @st.cache_resource for connections
29
+
30
+ Use for connections, API clients, ML models—objects that can't be serialized.
31
+
32
+ ```python
33
+ @st.cache_resource
34
+ def get_connection():
35
+ return st.connection("snowflake")
36
+
37
+ @st.cache_resource
38
+ def load_model():
39
+ return torch.load("model.pt")
40
+ ```
41
+
42
+ **Critical warning:** Never mutate `@st.cache_resource` returns—changes affect all users:
43
+
44
+ ```python
45
+ # BAD: Mutating shared resource
46
+ @st.cache_resource
47
+ def get_config():
48
+ return {"setting": "default"}
49
+
50
+ config = get_config()
51
+ config["setting"] = "custom" # Affects ALL users!
52
+
53
+ # GOOD: Copy before modifying
54
+ config = get_config().copy()
55
+ config["setting"] = "custom"
56
+ ```
57
+
58
+ **Cleanup with `on_release`:** Clean up resources when evicted from cache:
59
+
60
+ ```python
61
+ def cleanup_connection(conn):
62
+ conn.close()
63
+
64
+ @st.cache_resource(on_release=cleanup_connection)
65
+ def get_database():
66
+ return create_connection()
67
+ ```
68
+
69
+ ### TTL for fresh data
70
+
71
+ ```python
72
+ @st.cache_data(ttl="5m") # 5 minutes
73
+ def get_metrics():
74
+ return api.fetch()
75
+
76
+ @st.cache_data(ttl="1h") # 1 hour
77
+ def load_reference_data():
78
+ return pd.read_csv("large_reference.csv")
79
+ ```
80
+
81
+ **Guidelines:**
82
+ - Real-time dashboards → `ttl="1m"` or less
83
+ - Metrics/reports → `ttl="5m"` to `ttl="15m"`
84
+ - Reference data → `ttl="1h"` or more
85
+ - Static data → No TTL
86
+
87
+ ### Prevent unbounded cache growth
88
+
89
+ **Important:** Caches without `ttl` or `max_entries` can grow indefinitely and cause memory issues. For any cached function that stores changing objects (user-specific data, parameterized queries), set limits:
90
+
91
+ ```python
92
+ # BAD: Unbounded cache - memory will grow indefinitely
93
+ @st.cache_data
94
+ def get_user_data(user_id):
95
+ return fetch_user(user_id)
96
+
97
+ # GOOD: Bounded cache with TTL
98
+ @st.cache_data(ttl="1h")
99
+ def get_user_data(user_id):
100
+ return fetch_user(user_id)
101
+
102
+ # GOOD: Bounded cache with max entries
103
+ @st.cache_data(max_entries=100)
104
+ def get_user_data(user_id):
105
+ return fetch_user(user_id)
106
+ ```
107
+
108
+ Use `ttl` for time-based expiration OR `max_entries` for size-based limits. You usually don't need both.
109
+
110
+ ### Caching anti-patterns
111
+
112
+ **Don't cache functions that read widgets:**
113
+
114
+ ```python
115
+ # BAD: Widget inside cached function
116
+ @st.cache_data
117
+ def filtered_data():
118
+ query = st.text_input("Query") # Widget inside cached function!
119
+ return df[df["name"].str.contains(query)]
120
+
121
+ # GOOD: Pass widget values as parameters
122
+ @st.cache_data
123
+ def filtered_data(query: str):
124
+ return df[df["name"].str.contains(query)]
125
+
126
+ query = st.text_input("Query")
127
+ result = filtered_data(query)
128
+ ```
129
+
130
+ **Cache at the right granularity:**
131
+
132
+ ```python
133
+ # BAD: Caching too much - new cache entry per filter value
134
+ @st.cache_data
135
+ def get_and_filter_data(filter_value):
136
+ data = load_all_data() # Expensive!
137
+ return data[data["col"] == filter_value]
138
+
139
+ # GOOD: Cache the expensive part, filter separately
140
+ @st.cache_data(ttl="1h")
141
+ def load_all_data():
142
+ return fetch_from_database()
143
+
144
+ data = load_all_data()
145
+ filtered = data[data["col"] == filter_value]
146
+ ```
147
+
148
+ ## Fragments
149
+
150
+ Use `@st.fragment` to isolate reruns for self-contained UI pieces.
151
+
152
+ ```python
153
+ # BAD: Full app reruns
154
+ st.metric("Users", get_count())
155
+ if st.button("Refresh"):
156
+ st.rerun()
157
+
158
+ # GOOD: Only fragment reruns
159
+ @st.fragment
160
+ def live_metrics():
161
+ st.metric("Users", get_count())
162
+ st.button("Refresh")
163
+
164
+ live_metrics()
165
+ ```
166
+
167
+ For auto-refreshing metrics, use `run_every`:
168
+ ```python
169
+ @st.fragment(run_every="30s")
170
+ def auto_refresh_metrics():
171
+ st.metric("Users", get_count())
172
+
173
+ auto_refresh_metrics()
174
+ ```
175
+
176
+ Use for: live metrics, refresh buttons, interactive charts that don't affect global state.
177
+
178
+ ## Forms to batch interactions
179
+
180
+ By default, every widget interaction triggers a full rerun. Use `st.form` to batch multiple inputs and only rerun on submit.
181
+
182
+ ```python
183
+ # BAD: Reruns on every keystroke and selection
184
+ name = st.text_input("Name")
185
+ email = st.text_input("Email")
186
+ role = st.selectbox("Role", ["Admin", "User"])
187
+
188
+ # GOOD: Single rerun when user clicks Submit
189
+ with st.form("user_form"):
190
+ name = st.text_input("Name")
191
+ email = st.text_input("Email")
192
+ role = st.selectbox("Role", ["Admin", "User"])
193
+ submitted = st.form_submit_button("Submit")
194
+
195
+ if submitted:
196
+ save_user(name, email, role)
197
+ ```
198
+
199
+ Use `border=False` for seamless inline forms that don't look like forms:
200
+
201
+ ```python
202
+ with st.form("search", border=False):
203
+ with st.container(horizontal=True):
204
+ query = st.text_input("Search", label_visibility="collapsed")
205
+ st.form_submit_button(":material/search:")
206
+ ```
207
+
208
+ **When to use forms:**
209
+ - Multiple related inputs (signup, filters, settings)
210
+ - Text inputs where typing triggers expensive operations
211
+ - Any UI where "submit" semantics make sense
212
+
213
+ **When NOT to use forms:** If inputs depend on each other (e.g., selecting a country should update available cities), forms won't work since there's no rerun until submit.
214
+
215
+ ## Conditional rendering
216
+
217
+ **This is critical and often missed.**
218
+
219
+ Layout containers like `st.tabs`, `st.expander`, and `st.popover` always render all their content, even when hidden or collapsed.
220
+
221
+ To render content only when needed, use elements like `st.segmented_control`, `st.toggle`, or `@st.dialog` with conditional logic:
222
+
223
+ ```python
224
+ # BAD: Heavy content loads even when tab not visible
225
+ tab1, tab2 = st.tabs(["Light", "Heavy"])
226
+ with tab2:
227
+ expensive_chart() # Always computed!
228
+
229
+ # GOOD: Content only loads when selected
230
+ view = st.segmented_control("View", ["Light", "Heavy"])
231
+ if view == "Heavy":
232
+ expensive_chart() # Only computed when selected
233
+ ```
234
+
235
+ ```python
236
+ # BAD: Expander content always loads
237
+ with st.expander("Advanced options"):
238
+ heavy_computation() # Runs even when collapsed!
239
+
240
+ # GOOD: Toggle controls loading
241
+ if st.toggle("Show advanced options"):
242
+ heavy_computation() # Only runs when toggled on
243
+ ```
244
+
245
+ ## Pre-computation
246
+
247
+ Move expensive work outside the main flow:
248
+ - Compute aggregations in SQL/dbt, not Python
249
+ - Pre-compute metrics in scheduled jobs
250
+ - Use materialized views for complex queries
251
+
252
+ ## Large data handling
253
+
254
+ ### For datasets under ~100M rows
255
+
256
+ ```python
257
+ @st.cache_data
258
+ def load_data():
259
+ return pd.read_parquet("large_file.parquet")
260
+ ```
261
+
262
+ ### For very large datasets (over ~100M rows)
263
+
264
+ > **Note:** This is only an escape hatch when serialization becomes too slow. In most cases, data this large shouldn't be loaded entirely into memory—prefer using a database that queries and loads data on demand.
265
+
266
+ `@st.cache_data` uses pickle which slows with huge data. Use `@st.cache_resource` instead:
267
+
268
+ ```python
269
+ @st.cache_resource # No serialization overhead
270
+ def load_huge_data():
271
+ return pd.read_parquet("huge_file.parquet")
272
+
273
+ # WARNING: Don't mutate the returned DataFrame!
274
+ ```
275
+
276
+ ### Sampling for exploration
277
+
278
+ When exploring large datasets, load a random sample instead of the full data:
279
+
280
+ ```python
281
+ @st.cache_data(ttl="1h")
282
+ def load_sample(n=10000):
283
+ df = pd.read_parquet("huge.parquet")
284
+ return df.sample(n=n)
285
+ ```
286
+
287
+ ## Multithreading
288
+
289
+ Custom threads cannot call Streamlit commands (no session context).
290
+
291
+ ```python
292
+ import threading
293
+
294
+ def fetch_in_background(url, results, index):
295
+ results[index] = requests.get(url).json() # No st.* calls!
296
+
297
+ # Collect results, then display in main thread
298
+ results = [None] * len(urls)
299
+ threads = [
300
+ threading.Thread(target=fetch_in_background, args=(url, results, i))
301
+ for i, url in enumerate(urls)
302
+ ]
303
+ for t in threads:
304
+ t.start()
305
+ for t in threads:
306
+ t.join()
307
+
308
+ # Now display in main thread
309
+ for result in results:
310
+ st.write(result)
311
+ ```
312
+
313
+ **Prefer alternatives when possible:**
314
+ - `@st.cache_data` for expensive computations
315
+ - `@st.fragment(run_every="5s")` for periodic updates
316
+
317
+ ## References
318
+
319
+ - [Caching overview](https://docs.streamlit.io/develop/concepts/architecture/caching)
320
+ - [st.cache_data](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_data)
321
+ - [st.cache_resource](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_resource)
322
+ - [st.fragment](https://docs.streamlit.io/develop/api-reference/execution-flow/st.fragment)
323
+ - [st.form](https://docs.streamlit.io/develop/api-reference/execution-flow/st.form)
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: organizing-streamlit-code
3
+ description: Organizing Streamlit code for maintainability. Use when structuring apps with separate modules and utilities. Covers separation of concerns, keeping UI code clean, and import patterns.
4
+ license: Apache-2.0
5
+ ---
6
+
7
+ # Streamlit code organization
8
+
9
+ For most simple apps, keep everything in one file—it's cleaner and more straightforward. The app file should read like a normal Python script for data processing, with a few Streamlit commands sprinkled in.
10
+
11
+ Name the main file `streamlit_app.py` (Streamlit's default).
12
+
13
+ ## When to split
14
+
15
+ **Keep in one file (most apps):**
16
+ - Apps under ~1000 lines
17
+ - One-off scripts and prototypes
18
+ - Apps where logic is straightforward
19
+
20
+ **Consider splitting when:**
21
+ - Data processing is complex (50+ lines of non-UI code)
22
+ - Multiple pages share logic
23
+ - You want to test business logic separately
24
+
25
+ If splitting makes sense, here's how to organize it.
26
+
27
+ ## Directory structure
28
+
29
+ ```
30
+ my-app/
31
+ ├── streamlit_app.py # Main entry point
32
+ ├── app_pages/ # Page UI modules
33
+ │ ├── dashboard.py
34
+ │ └── settings.py
35
+ └── utils/ # Business logic & helpers
36
+ ├── data.py
37
+ └── api.py
38
+ ```
39
+
40
+ ## Separating UI from logic
41
+
42
+ When you do split, keep Streamlit files focused on UI and move complex logic to utility modules:
43
+
44
+ ```python
45
+ # streamlit_app.py - UI-focused
46
+ import streamlit as st
47
+ from utils.data import load_sales_data, compute_metrics
48
+
49
+ st.title("Sales Dashboard")
50
+
51
+ start = st.date_input("Start")
52
+ end = st.date_input("End")
53
+
54
+ data = load_sales_data(start, end)
55
+ metrics = compute_metrics(data)
56
+
57
+ st.metric("Revenue", f"${metrics['revenue']:,.0f}")
58
+ st.dataframe(data)
59
+ ```
60
+
61
+ ## Avoid if __name__ == "__main__"
62
+
63
+ Streamlit apps run the entire file on each interaction. Don't use the main guard in Streamlit files.
64
+
65
+ ```python
66
+ # BAD - don't do this in streamlit_app.py or pages
67
+ if __name__ == "__main__":
68
+ main()
69
+
70
+ # GOOD - just put the code directly
71
+ import streamlit as st
72
+
73
+ st.title("My App")
74
+ ```
75
+
76
+ The main guard is fine in utility modules for quick testing:
77
+
78
+ ```python
79
+ # utils/data.py
80
+ def load_data(path):
81
+ ...
82
+
83
+ # Optional: test this module directly with `python utils/data.py`
84
+ if __name__ == "__main__":
85
+ print(load_data("test.csv"))
86
+ ```
87
+
88
+ ## References
89
+
90
+ - [Multipage apps](https://docs.streamlit.io/develop/concepts/multipage-apps)
91
+ - [st.cache_data](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_data)