Taste

Local-first preference-learning runtime for Clew Code.

Taste learns your coding style from accept, reject, edit, test, lint signals and manual rules. It combines symbolic rules, semantic preference scoring, and contextual bandit optimization to adapt Clew's output to your preferences.

It does not fine-tune the base LLM. All learning is local, online, and preference-based.

What It Learns

  • Code style — formatting, naming conventions, preferred patterns
  • Architecture — module structure, dependency direction, layering
  • Tooling — preferred build tools, linters, test frameworks
  • Testing — test style, coverage expectations, mocking patterns
  • Naming — variable, function, and class naming conventions
  • Security — safe patterns vs unsafe patterns
  • Performance — efficient algorithms, caching, resource management
  • UI patterns — component structure, state management, styling approach
  • Workflow — commit style, review preferences, deployment habits

What It Does Not Do

  • Does not fine-tune or modify the base LLM
  • Does not send taste data to remote services (all data stays local)
  • Does not automatically block edits without showing a reason
  • Does not replace memory, skills, or CLAUDE.md files

How It Differs from Other Systems

System Purpose Storage Scope
CLAUDE.md Project instructions .claude/ files Static project rules
Memory Cross-session facts memdir/ Recall
Skills Reusable procedures Plugin/skill system Task automation
Taste Learned preferences .clew/taste/ Adaptive preference optimization
  • Rules are explicit user preferences
  • Memory is facts about the user and project
  • Skills are reusable task procedures
  • Taste is learned, weighted preference signals

Storage Paths

Data Path
Project profile .clew/taste/profile.json
Project event log .clew/taste/events.jsonl
Project packages .clew/taste/packages/
Global profile ~/.clew/taste/profile.json
Global packages ~/.clew/taste/packages/

Commands

Command Description
/taste Open interactive menu (arrow-key navigable)
/taste status Print status
/taste learn <rule> Add a manual rule
/taste forget <id> Remove a rule by ID
/taste profile Show full profile with rules
/taste events Show recent learning events
/taste decay Apply confidence decay
/taste eval Run profile self-evaluation
/taste export Export high-confidence rules
/taste import <file> Import rules from file
/taste on Enable taste
/taste off Disable taste

Configuration

Settings in settings.json:

json
{
  "taste": {
    "enabled": true,
    "autoLearn": true,
    "injectPrompts": true,
    "validateEdits": true,
    "minConfidence": 0.55,
    "maxInjectedRules": 8,
    "decayEnabled": true,
    "banditEnabled": true,
    "neuralScoringEnabled": true
  }
}

Architecture

Taste consists of several subsystems:

  1. Signal Collection — Captures accept, reject, edit, test, lint, and tool signals from user interactions and converts them into learning events.
  2. Reward Model — Maps signal types to numeric reward values (accept = +1.0, reject = -1.0, test pass = +0.4, etc.) and computes edit distance rewards dynamically.
  3. Symbolic Engine — Compiles high-confidence rules into checkable constraints. Rules with confidence >= 0.85 can block edit acceptance. Rules below threshold warn without blocking. Never blocks silently.
  4. Neural Scorer — Provider-agnostic lexical similarity scoring (Jaccard/TF-IDF) that scores candidate output against active rules. Extensible to use embedding APIs when available.
  5. Contextual Bandit — Epsilon-greedy bandit with 6 strategy arms (minimal, strict_style, architecture_first, test_first, safety_first, refactor_heavy). Selects optimal strategy based on feedback and context features.
  6. Prompt Injection — Injects a compact <clew_taste> block into the system prompt with relevant rules. Max 8 rules by default, filtered by confidence and sorted by relevance.
  7. Decay Engine — Gradual confidence reduction for unused rules (half-life based, default 30 days). Prevents stale preferences from persisting.
  8. Event Log — Append-only JSONL file storing all raw learning events for auditability and regression analysis.

Continuous RL (Local Online Preference Optimization)

Taste implements local online preference optimization:

  • Online — learns continuously from each interaction, no batch training
  • Local — all computation and storage stays on the user's machine
  • Preference-based — optimizes for user preferences via reward signals
  • Multi-objective — balances style, correctness, safety, and efficiency

The learning loop:

  1. User interacts with Clew (accepts, rejects, edits output)
  2. Signal collector captures the interaction as a typed event with reward
  3. Bandit arm updates based on reward signal
  4. Rule confidence adjusts based on positive/negative evidence
  5. Prompt injection adapts to reflect current learned preferences
  6. Decay gradually reduces stale rule confidence

This is not LLM fine-tuning. The base model's weights never change. Taste adapts the prompt context and edit validation, not the model itself.

Privacy

  • All taste data stays local by default
  • Profiles and event logs are stored in .clew/taste/ or ~/.clew/taste/
  • No data is sent to remote services
  • Export/import is explicit and user-initiated
  • Event logs are append-only for auditability

Integration Points

Point Status Description
Prompt injection Implemented System prompt taste block via TastePromptInjector
Edit validation Implemented validateEdit() called in FileEditPermissionRequest
Accept/reject signals Implemented Fire-and-forget via recordAcceptSignal / recordRejectSignal in PermissionContext
Test/lint signals No-op stub Ready for PostToolUse output analysis
Tool result signals Implemented recordToolSignal() in toolExecution.ts
Interactive menu Implemented /taste Dialog with 11 actions, Spinner loading, input pre-fill
Status line Implemented TasteStatusLine shown in PromptInputFooter
Config live-reload Implemented subscribeToSettingsChanges() reloads config at runtime
Settings config Implemented taste.* in settings.json

Example Usage

/taste                           # Open interactive menu
/taste learn Use const instead of let
/taste learn Prefer named exports
/taste learn Never use any type
/taste status
/taste profile
/taste eval
/taste export