How it works

Deterministic engines, an agent that explains them.

Where the data comes from, how ranking and scoring work, why the advisor is an agent, and what it is and isn't allowed to do.

01

Why it exists

Know what you have

A shelf of twelve bottles is hard to see as a whole. Sillage maps it: families, signature accords, which seasons and occasions you can actually cover.

Buy the right next one

Recommendations start from what you own and what you've said you like, and every pick explains itself, so you can tell a real gap from a fifth version of the same scent.

Use what you own better

Most collections are under-worn. Today picks from your own shelf; Scent Lab helps you try pairings and learn from how they actually wore.

The bet is that collection context makes advice much more relevant, and that it's only trustworthy if every claim traces back to data. That's a hypothesis: the evals test that the system behaves as designed, not yet that people prefer it.

02

Where the data comes from

About 38,000 fragrances with notes, accords and community votes come from Fragrantica's public pages via the open Decant dataset. Sillage keeps facts and aggregates only (note pyramids, accord strengths, ratings, longevity, projection, season and day/night votes, short review themes) and links each page back to its source.

When search finds nothing, Open Beauty Facts is queried live. Those listings have no notes, so they're marked unverified and can be collected but not recommended.

Prices aren't in the data. Budget filtering uses estimated price bands from each brand's typical pricing (395 brands), always labelled as estimates. Real prices only come from the price check.

Occasion fit isn't in the data either. It's inferred from day/night votes, projection and accords, labelled “estimated” wherever it appears, and lowers confidence.

03

How recommendations are ranked

Tested code, not a language model: the same shelf and filters give the same answer. Every result carries reasons and caveats, and every exclusion is counted.

  1. 1

    Taste profile

    Each bottle contributes its accords, weighted by your rating: love 1.0, like 0.7, neutral 0.2, unrated 0.15, dislike counts against.

  2. 2

    Hard filters

    Owned bottles, notes you avoid (oud also catches agarwood), budget, season, time of day and marketing preference. Different drops near-copies (≥ 75% overlap); Fill gaps drops ≥ 85%.

  3. 3

    Score

    Taste fit, the mode's goal, budget, season/time and performance, weighted per mode (below).

  4. 4

    Diversify

    At most two picks per brand; other versions of a bottle you own are flagged, and budget alternatives are labelled with what they resemble.

Weights by mode
RowTasteGoalBudgetSeason/timePerformance
Similar35%25%20%10%10%
Different35%25%20%10%10%
Fill gaps25%35%20%10%10%

04

Collection Score, Today and Scent Lab

Three features on one shared fragrance profile. Every number is calculated by versioned code; when data is missing, that factor is left out and the rest reweighted. It never counts as zero.

Collection Score

How far your shelf reaches, 0–100. A coverage description, never a judgement of taste, and owning more doesn't raise it by itself. Preview any bottle to see the change before you buy.

Dimensions
Season coverage25%
Occasion coverage25%
Versatility20%
Scent diversity15%
Low redundancy15%

Today

Ranks only bottles you own for an occasion, time of day, weather and intensity. Weather is manual unless you choose to share location, which is rounded and never stored.

Factors
Occasion30%
Weather25%
Intensity15%
Preference15%
Time of day10%
Rotation (under-worn)5%

Scent Lab

A labelled heuristic for two of your bottles, from a small editable ruleset of complementary and tension accords. Not chemistry. Your wear ratings move similar pairings by at most ±10 points.

Components
Accord complementarity35%
Low clash risk25%
Intensity balance20%
Family balance10%
Your preference10%

05 · The advisor agent

Why an agent, and why only one.

A question like “a woody winter scent under $150 that isn't like anything I own” isn't one lookup. It means reading the shelf, translating “isn't like anything I own” into Different mode, setting the season and budget, checking the top pick more closely, and explaining the trade-offs. A fixed pipeline handles one shape of question; an agent can plan the steps for each one.

What the agent doesn't do matters as much. It doesn't rank fragrances, score collections or pair bottles itself: deterministic, tested engines do, and the agent calls them as tools. That keeps the numbers reproducible and the language flexible.

One agent with ten typed tools is enough for this job. A multi-agent setup would add cost, latency and failure modes without a clear benefit, so it was left out on purpose.

The loop is model-agnostic. It runs on Google Gemini's free tier today and on Anthropic's Claude with one environment variable; the tools, the six-round cap and the grounding check are identical either way, and every answer's trace names the model that wrote it.

  1. You

    “A woody winter scent under $150 that isn't like anything I own?”

1 / 7
A worked example in the advisor's real format. In the app, every answer shows its own trace with latency and cost.

The loop

  1. 01

    Read

    Starts from your shelf and preferences, every time. A recommendation that doesn't know what you own is just a search.

  2. 02

    Decide

    Chooses which engine fits the question: Similar, Different or Fill gaps; the score; today's pick; a price check.

  3. 03

    Act

    Calls the tool with typed, validated inputs. Parallel calls where it can, at most six rounds in total.

  4. 04

    Inspect

    Reads the results, and looks closer at the best candidate when the answer depends on it.

  5. 05

    Check

    Before you see anything, every cited fragrance and price is matched against what the tools returned.

  6. 06

    Answer

    Explains in plain English, with each pick linked and the engine's caveats kept.

Its tools

get_user_profileShelf size, family mix, season and day/night coverage, preferencesread
get_owned_fragrancesEach bottle and how you rated it (ownership alone isn't treated as liking)read
search_catalogResolve a fragrance you mention by nameread
get_fragrance_detailsNotes, accords, community votes, review themes (labelled untrusted)read
recommend_candidatesRuns Discover's deterministic ranking engineread
find_offersVariant-matched price check for one exact bottleread
get_collection_scoreYour Collection Score, its five dimensions, strengths and gapsread
pick_for_todayRanks only bottles you own for an occasion, time and temperatureread
propose_add_to_wishlistShows you a confirm button; saves nothing by itselfpropose
propose_preference_updateA note to avoid, a liked note or a budget, for you to confirmpropose

Guardrails and failure modes

  • Output contract. Fragrances are cited by id. Any id that didn't come back from a tool in that turn, and any dollar amount that didn't appear in a tool result, is removed and counted in the trace. In the eval, 0 of 7 planted fabrications got through.
  • No silent writes. Saving or changing preferences goes through “propose” tools that render a confirm button. The model never touches the database.
  • Prompt injection. Review themes and product names come from third parties and are labelled untrusted in tool results; with no write tools, there's nothing for injected text to trigger.
  • Bounded cost. Six tool rounds at most, low reasoning effort, prompt caching on the fixed instructions and tools, 20 questions per person per hour; every answer shows its tokens, latency and estimated cost.
  • Graceful degradation. With no model, or on an error or decline, a rule-based mode answers recommendations, score and “what to wear” questions with the same engines, and says so.
  • Same rules elsewhere. Today's explanation can be phrased by the model, but only from the ranker's factors: if it names the wrong bottle or introduces a new number, the template is used instead.

06

How prices are matched

  • You choose the exact bottle: concentration and size. A fragrance can be found before its size is known, but not priced until it is.
  • An exact match needs the same brand, name, concentration and size, and a new, full, single bottle. Testers, samples, refills, gift sets, pre-owned and flankers are set aside.
  • Unknown extra words (“Qahwa”, “Lucky”) go to “Needs verification”. The first version used a blocklist and the eval caught it calling flankers exact.
  • Live results come from Google Shopping via SerpApi, cached 6 h, 12 checks per person per hour. Otherwise you see labelled sample offers from fictional stores, with no links. Never “cheapest anywhere”.

07

Privacy and security

  • Everything you own, rate, wear, pair or ask is locked to your account in the database itself (row-level security), with tests that one user can't read another's data.
  • API keys stay on the server; the privileged database key is used only for shared caches, rate limits and demo sandboxes.
  • Location for live weather is optional, rounded to about 10 km, used once and never stored.
  • Product analytics record only an allowlist of event names and safe properties: never notes, location or chat text.

Privacy notice · Decision register · Evals