Exploring Jev for contextual playlists
I built a small Spotify-connected Tagify prototype and used Jev experiments to learn where probabilistic decisions help—and where product constraints matter more.
Why I built this
I wanted hands-on experience with Jev, not just another chat interface wrapped around a music app.
The question that interested me was narrower: could a model help with the contextual decisions behind a playlist? A song can be a personal favorite and still be wrong for a quiet evening. A track can be energetic but too aggressive for a night drive. And a song that someone has started skipping should probably be treated differently from one they have saved for years.
Jev seemed like a good fit for that question because it returns structured choices, scores, and probabilities instead of text. I could describe a small listening situation, ask whether a song belonged, and inspect the result rather than trying to parse an explanation from a chat response.
This became an experiment inside Tagify, a project I am using to explore personal music tags, contextual preferences, and explainable playlist building.
What I built
I built a local Spotify connection for Tagify using Authorization Code with PKCE and the user-library-read scope. The app validates the OAuth state, pages through saved tracks 50 at a time, skips unavailable tracks, and stores imported metadata alongside personal tags in local storage.
There was a small but revealing implementation detail: Spotify requires an exact redirect URI match. For local development, it permits HTTP on a loopback IP such as 127.0.0.1, but not on localhost. I used a fixed loopback callback and made the app return there before starting authorization. Spotify’s redirect URI rules are strict about this.
I also learned that Spotify shapes the architecture as much as the model does. New Web API use cases cannot rely on Recommendations, Audio Features, or Audio Analysis, so I could not build Tagify around Spotify’s own recommendation signals. Spotify’s Web API changes pushed the project toward personal tags and user-owned signals instead.
Rate limiting is another practical constraint. Spotify calculates limits over rolling 30-second windows and returns 429 responses with a Retry-After header. The importer therefore needs pagination and backoff rather than a burst of requests. Spotify’s rate-limit guidance makes that expectation explicit.
The biggest boundary was between Spotify and Jev. Spotify’s developer policy says not to train or otherwise ingest Spotify content into an AI or machine-learning model. The policy means the production design keeps Spotify metadata in the catalog and UI path. A future Jev adapter should receive opaque track IDs, user-created tags, preferences, and listening signals—not Spotify titles, artists, or audio features.
For the local Jev experiment, I used a deliberately small fixture with recognizable songs and normal personal tags: “Midnight City” for a night drive, “Pink + White” for a mellow setting, and “One More Time” for a party. I ran seven conditions five times each, asking Jev which song fit best and whether each song should be included.
What I learned
The obvious scenarios worked well. “Pink + White” reached a 95.6% inclusion probability for quiet reading, while “One More Time” reached 95.0% for a house party.
The less obvious cases were more interesting. When I described “Midnight City” as a slow alternate version, its night-drive inclusion probability dropped from 95.4% to 23.0%. When I left the musical fit alone but said the listener now usually skips it early, it dropped to 40.2%. Jev appeared to weigh both immediate fit and user behavior, with a direct mismatch carrying more weight.
Prompt wording also mattered. Reframing “One More Time” with a warning that its energy could overpower an atmospheric playlist reduced its inclusion probability from 10.8% to 6.8%. That is not a reason to distrust the model, but it is a reason to treat wording as product behavior: version it, test it, and avoid assuming that equivalent phrasing is equivalent input.
The most useful failure was the discovery condition. Every candidate had a low inclusion probability, but Jev still selected a “best” song because my question forced a choice. A real playlist builder needs a none_of_these option or an explicit inclusion threshold before accepting a winner.
After 35 requests, the results were stable across repeated runs, usually varying by only a few percentage points and averaging about 194 ms per call. That gives me enough confidence to continue experimenting, but not enough to claim that Jev improves recommendations for real users.
Next time
Jev makes the most sense in Tagify as a bounded decision layer after ordinary code has filtered a library by tags, recency, exclusions, and duration. It should help rerank a small shortlist, not search an entire library, calculate scores, or invent a tag system.
The next experiment will use opaque IDs and user-created signals instead of recognizable-song fixtures. I want to compare Tagify’s deterministic scorer with Jev on expected choices, thresholds, latency, cost, skips, saves, and playlist removals. That will turn this from an API experiment into evidence about whether it improves the product.