# 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