Dependency & unused-library audit
Every finding on this page was verified by grepping actual imports across
frontend/app, frontend/src, frontend/modules, and all backend/**/*.py. A
package is only called "unused" where a grep found no usage and it is not a
required transitive/peer/plugin dependency.
Frontend — remove or relocate
| Package | Evidence | Action |
|---|---|---|
react-native-dotenv | 0 imports; no @env usage; no babel.config.js to even wire its plugin. All env access is process.env.EXPO_PUBLIC_*. A vestigial expo.doctor exclude still names it. | Remove — low risk |
react-native-webview | 0 hits for WebView anywhere. The "widget preview" justification is stale — modules/drape-widget is a native Swift widget, not a WebView. | Remove — low risk |
expo-symbols | 0 hits for expo-symbols / SymbolView / SFSymbol. | Remove — low risk |
@expo/ngrok | 0 imports; a dev-only tunnel binary sitting in dependencies. | Move to devDependencies |
expo-web-browser | Declared as an app.json plugin but 0 JS usage. | Verify no redirect flow depends on it, then remove — low/medium confidence |
Confirmed in use (keep): @expo/vector-icons (46 imports), expo-router
(50), react-native-safe-area-context (45), @react-native-async-storage/async-storage
(26), expo-image (13), expo-linear-gradient (8), react-native-svg,
posthog-react-native, expo-image-picker, expo-camera, expo-file-system,
expo-haptics, the three Google-font packages, @sentry/react-native,
react-native-view-shot (share cards), and expo-image-manipulator (loaded via a
dynamic import() in body-photo.tsx).
Used indirectly — do not remove: posthog-react-native-session-replay (native
autolinked peer), react-native-screens / react-native-gesture-handler /
react-native-reanimated / react-native-worklets (navigation + Expo infra),
react-native-web / react-dom (web build target), and the various expo-*
router internals.
The directly-listed @react-navigation/* and @expo/metro-runtime packages are
guaranteed transitively by expo-router — removing them declutters the manifest
but forfeits version pinning, so it is optional and low priority.
Backend — the big win
The backend requirements.txt is a full pip freeze (157 pinned lines). The
code actually imports roughly 25 top-level packages. Entire stacks are
installed that nothing imports:
Each package below returned 0 import matches repo-wide and is not a transitive dependency of anything used:
| Package(s) | Why it is bloat |
|---|---|
litellm (+ tiktoken, tokenizers, huggingface_hub, hf-xet) | Langfuse does not require litellm; came in as an unused stack |
google-genai, google-generativeai, google-ai-generativelanguage, google-api-python-client, google-auth* (+ gRPC/proto tree) | Drape uses OpenAI + fal.ai + Fashn, never Gemini/Google |
boto3, botocore, s3transfer | Storage is Supabase, not S3 |
pandas | Never imported |
pyiceberg (+ pyroaring, strictyaml, mmh3, zstandard, fsspec) | Apache Iceberg — not in the architecture |
s5cmd, jq, fastuuid, passlib, librt | Unused CLIs / libs (bcrypt and stdlib uuid are what's actually used) |
requirements.txt anti-patterns
- Full-freeze, no direct/transitive split. 157 pinned lines mix true direct
deps with internals like
h11,hpack,anyio,yarl. Upgrades are brittle and the ~25 real deps are hidden. - Dev tooling installed in production.
black,flake8,isort,mypy,pytest,pycodestyle,pyflakes,mccabe,pathspec, and friends are installed on a 512 MB Render free tier. There is norequirements-dev.txt. - Inconsistent pinning. Every line is
==-pinned except the first,anthropic>=0.40.0— andanthropicis only used by a dev cron agent (agents/bug_fixer.py), so it does not belong in the production file. - Orphaned transitives.
ecdsaandrsa(classicpython-josedeps) remain even thoughpython-josewas removed — the freeze was never regenerated cleanly.
python-jose is not present and imported nowhere — server.py uses
import jwt as pyjwt (PyJWT). There is no CVE-2024-33663 / 33664 exposure. The
2026-05-25 audit docs claim the opposite ("python-jose is used, remove PyJWT") —
that is inverted and stale, and should be corrected.
Prioritized cleanup
Tier 1 — safe, quick (low risk):
- Frontend: remove
react-native-dotenv,react-native-webview,expo-symbols; move@expo/ngroktodevDependencies. Then reinstall + an Expo build smoke test. - Backend: create
requirements-dev.txtand move the ~13 dev tools out of prod.
Tier 2 — remove unused heavy stacks (low–medium risk):
- Drop the Google AI, AWS, litellm, pandas, and Iceberg stacks plus their orphaned transitives. Expected to cut the install by well over half.
- Move
anthropic(pinned) andrequeststo the dev file — both are agent-script-only. - Risk surface is the re-freeze. Rebuild in a clean venv, reinstall the
curated direct list, and verify
import serversucceeds before deploying — following the manual-deploy + staging-smoke-test rules.
Tier 3 — follow-ups (housekeeping):
- If the legacy
POST /api/previews/generateendpoint is deleted (no frontend callers, its key already removed), theopenaiimport becomes removable too. - Correct the two stale audit docs.
Net effect: the frontend sheds three to four real dependencies; the backend
requirements.txt drops from 157 pinned lines to roughly 25 curated production
deps plus a separate dev file.