How Taste Closet is built on Claude.
Working notes from Purify Solution. The product is in development; anything not built yet is marked planned.
Tool schemas
Look planning and shopping checks run as a Claude tool-use loop. The model can only choose item IDs returned by search_closet (or, later, search_catalog), and every candidate goes through deterministic checks.
[
{"name": "tag_garment",
"description": "Vision: tag one garment photo into the Garment schema.",
"input_schema": {"type": "object",
"properties": {"image_id": {"type": "string"}},
"required": ["image_id"]}},
{"name": "search_closet",
"description": "Find the user's own items matching filters.",
"input_schema": {"type": "object", "properties": {
"category": {"enum": ["top","bottom","outer","dress","shoes","bag","accessory"]},
"season": {"enum": ["spring","summer","autumn","winter"]},
"formality_min": {"type": "integer", "minimum": 1, "maximum": 5},
"formality_max": {"type": "integer", "minimum": 1, "maximum": 5},
"colors": {"type": "array", "items": {"type": "string"}},
"exclude_ids": {"type": "array", "items": {"type": "string"}}}}},
{"name": "get_weather",
"description": "Hourly forecast for a city and date.",
"input_schema": {"type": "object", "properties": {
"city": {"type": "string"}, "date": {"type": "string", "format": "date"}},
"required": ["city", "date"]}},
{"name": "score_outfit",
"description": "Deterministic rule checks for a candidate look.",
"input_schema": {"type": "object", "properties": {
"item_ids": {"type": "array", "items": {"type": "string"}},
"temp_c": {"type": "number"}, "occasion_formality": {"type": "integer"}},
"required": ["item_ids"]}},
{"name": "check_fit",
"description": "Compare an item's size chart and silhouette with the user's sizes.",
"input_schema": {"type": "object", "properties": {
"item_ref": {"type": "string"}, "size": {"type": "string"}},
"required": ["item_ref"]}},
{"name": "check_color_harmony",
"description": "Score a color against owned items; returns matching item IDs.",
"input_schema": {"type": "object", "properties": {
"hex": {"type": "string", "pattern": "^#[0-9a-f]{6}$"}},
"required": ["hex"]}},
{"name": "check_budget",
"description": "Compare a price with the user's budget for the category.",
"input_schema": {"type": "object", "properties": {
"price_krw": {"type": "integer"}, "category": {"type": "string"}},
"required": ["price_krw", "category"]}}
]// Planned, not built yet
search_catalog(season | item_type, filters) -> candidate items from partner/affiliate catalogs
get_calendar_context(date) -> occasions + formality hintsGarment JSON schema
Vision tagging uses structured outputs against this schema. Responses that fail validation are retried once with the validator errors attached, then shown to the user to fix by hand.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Garment",
"type": "object",
"required": ["category", "subcategory", "colors", "pattern",
"material", "fit", "seasons", "formality", "confidence"],
"properties": {
"category": {"enum": ["top","bottom","outer","dress","shoes","bag","accessory"]},
"subcategory": {"type": "string", "maxLength": 40},
"colors": {
"type": "array", "minItems": 1, "maxItems": 3,
"items": {"type": "object",
"properties": {"name": {"type": "string"},
"hex": {"type": "string", "pattern": "^#[0-9a-f]{6}$"},
"share": {"type": "number"}}}
},
"pattern": {"enum": ["solid","stripe","check","dot","floral","graphic","other"]},
"material": {"type": "string"},
"fit": {"enum": ["slim","regular","relaxed","oversized","n/a"]},
"silhouette": {"enum": ["straight","tapered","wide","a-line","boxy","fitted","n/a"]},
"seasons": {"type": "array", "items": {"enum": ["spring","summer","autumn","winter"]}},
"formality": {"type": "integer", "minimum": 1, "maximum": 5},
"mood_tags": {"type": "array", "maxItems": 6, "items": {"type": "string"}},
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
},
"additionalProperties": false
}Taste profile JSON schema
Seeded by the onboarding quiz, then updated from likes, dislikes, saved looks and direct edits.
{
"title": "TasteProfile",
"type": "object",
"required": ["styles", "palette", "fit", "sizes", "budget_krw"],
"properties": {
"styles": {"type": "array", "items": {"type": "object",
"properties": {"tag": {"type": "string"},
"weight": {"type": "number", "minimum": 0, "maximum": 1}}}},
"palette": {"type": "array", "maxItems": 8,
"items": {"type": "string", "pattern": "^#[0-9a-f]{6}$"}},
"avoid": {"type": "array", "items": {"type": "string"}},
"fit": {"type": "object", "properties": {
"tops": {"enum": ["slim","regular","relaxed","oversized"]},
"bottoms": {"enum": ["straight","tapered","wide"]}}},
"sizes": {"type": "object", "properties": {
"top": {"type": "string"}, "bottom_waist_cm": {"type": "number"},
"shoe_mm": {"type": "integer"}}},
"formality_range": {"type": "array", "items": {"type": "integer"}, "minItems": 2, "maxItems": 2},
"budget_krw": {"type": "object", "additionalProperties": {"type": "integer"}},
"source": {"enum": ["quiz", "feedback", "user_edit"]}
}
}Validation rules
- Existence: every item ID must belong to the user's closet (or the candidate catalog result).
- Slots: at most one item per slot (top, bottom or dress, outer, shoes); outer required below a temperature threshold.
- Weather fit: seasons and warmth must suit the forecast; rain excludes suede and canvas shoes.
- Formality: each item within ±1 of the occasion's formality level.
- Color harmony: neutral base, at most one high-saturation accent, rule-based palette check.
- Shopping checks: fit vs the user's sizes and silhouettes, material vs preferences and season, color vs owned items, mood vs style profile, price vs budget. All five are reported; failures are shown, never hidden.
- Freshness: avoid repeating the same top within the user's chosen window.
Model routing
| Task | Model tier | Why |
|---|---|---|
| Garment tagging (vision) | Smaller, faster Claude model | High volume, narrow schema, easy to evaluate |
| Quick swaps | Smaller model | Constrained search inside a known look |
| Taste & closet analysis | Larger Claude model | Interpretation across the whole closet |
| Daily, situation and capsule looks | Larger model | Multi-step tool use and trade-offs |
| Shopping verification (planned) | Larger model + deterministic checks | Checks in code; model explains trade-offs |
Prompt caching
The system prompt, tool definitions, the taste profile and a compact JSON summary of the user's closet form a stable prefix marked for prompt caching. Per-request inputs (date, weather, situation, shopping query) come after it. The cache is invalidated when the closet or taste profile changes.
Evaluation plan
| Eval | Metric | Status |
|---|---|---|
| Tagging accuracy vs human labels | Per-field accuracy (category, pattern, fit, formality); color match | In progress |
| Schema validity | Share of tagging responses valid on first try | In progress |
| Outfit rule checks | Pass rate on weather fit, formality, color harmony | Planned |
| Situation looks | Human rating on a fixed set of situation prompts | Planned |
| Shopping verification | Check agreement with human judgment on fit, color, price | Planned |
| Grounded explanations | Reasons consistent with tool results | Planned |
| Cost and latency | Tokens, cache hit rate, p50/p95 latency per route | Planned |
No results are published yet; no metrics are claimed on this site.
Privacy of user photos
When the app launches, closet photos are planned to be processed by the Claude API for tagging, and we plan to keep the structured tags rather than the photos wherever possible. Today the website collects only waitlist sign-ups. See the privacy page.
How we build
Taste Closet is developed with Claude Code. This site is static and hosted on Cloudflare Pages.