npm package: @mise-en-scene/taste-memory
Description: Aesthetic intelligence MCP server — taste memory for AI design agents
Latest version: 0.1.3

# @mise-en-scene/taste-memory

Aesthetic intelligence MCP server. Stores taste observations, design decisions, anti-patterns, and reference analyses in SQLite. Builds taste profiles that persist across sessions — the agent develops real preferences over time.

## MCP Tools

| Tool | Input | Description |
|------|-------|-------------|
| `taste_remember` | `type`, `scope`, `data`, `reasoning?`, `project?` | Store a taste observation |
| `taste_recall` | `query`, `type?`, `scope?`, `project?`, `limit?` | Search taste memory by text |
| `taste_profile` | `scope` (`user` / `project` / `merged`), `project?` | Get aggregated taste profile |
| `taste_decide` | `chosen`, `rejected`, `reason`, `project?` | Record a design decision |
| `taste_reference` | `project`, `analysis`, `image_path?` | Store a reference analysis |
| `taste_system` | `project`, `tokens?` | Get or set design system tokens |

## Usage

### As an MCP Server

The package runs as a stdio MCP server. Configure it in your `.mcp.json`:

```json
{
  "mcpServers": {
    "mise-en-scene-taste-memory": {
      "command": "npx",
      "args": ["@mise-en-scene/taste-memory"]
    }
  }
}
```

Or run directly:

```bash
npx mise-en-scene-taste-memory
```

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `MISE_TASTE_DB` | `~/.mise-en-scene/taste.db` | SQLite database path |

### Programmatic Usage

```typescript
import { createDatabase, closeDatabase } from '@mise-en-scene/taste-memory/db';
import { TasteStore } from '@mise-en-scene/taste-memory/store';
import { TasteSearch } from '@mise-en-scene/taste-memory/search';
import { buildProfile } from '@mise-en-scene/taste-memory/profile';

// Initialize
const db = createDatabase('/path/to/taste.db');
const store = new TasteStore(db);
const search = new TasteSearch(db);

// Store observations
store.remember('palette', 'user', {
  dominant: '#1a1a2e',
  accent: '#e94560',
}, { reasoning: 'Dark moody palette with warm accent' });

store.remember('anti-pattern', 'user', {
  rejected: 'Roboto',
  context: 'too generic',
}, { reasoning: 'AI default font' });

// Record decisions
store.decide(
  { layout: 'asymmetric' },
  { layout: 'centered' },
  'Asymmetric creates visual tension',
  'wine-label'
);

// Store reference analysis
store.storeReference('wine-label', {
  colors: ['#f5f0e8', '#c9a96e'],
  typography: 'transitional serif + humanist sans',
  mood: ['luxury', 'warm'],
  cultural_context: 'French wine label tradition',
});

// Search
const results = search.textSearch('editorial dark premium');
const decisions = search.searchDecisions('layout', 'wine-label');

// Build profile
const profile = buildProfile(store, 'merged', 'wine-label');

// Cleanup
closeDatabase();
```

## Data Model

### Taste Types

| Type | What It Captures |
|------|-----------------|
| `palette` | Color choices — dominant, secondary, accent |
| `typography` | Font preferences, pairings, classifications |
| `layout` | Composition patterns, grid preferences |
| `texture` | Surface treatments — grain, gradients, shadows |
| `mood` | Emotional descriptors — "editorial", "warm", "refined" |
| `anti-pattern` | Things to avoid — "generic gradients", "Roboto" |

### Scopes

| Scope | Persists Across |
|-------|----------------|
| `user` | All projects — your personal aesthetic |
| `project` | Single project — project-specific choices |
| `merged` | Both combined, project overrides user |

### Database Schema

Four tables in SQLite with WAL mode:

- **`taste_entries`** — Observations with type, scope, JSON data, reasoning, timestamps
- **`taste_decisions`** — Chosen vs rejected options with reasoning
- **`taste_references`** — Reference image analyses with structured extraction
- **`design_systems`** — Design tokens per project (upsert on conflict)

## Search

Text search uses token-based similarity scoring (Jaccard-style overlap). Queries are tokenized, matched against stored entry data and reasoning fields, and ranked by relevance.

```typescript
// Search with filters
const results = search.textSearch('warm editorial', {
  type: 'palette',
  scope: 'user',
  limit: 10,
});
```

## Development

```bash
npm test                # Run tests (24 unit + 2 integration)
npm run build           # Compile TypeScript
npm run test:watch      # Watch mode
```