Cellarbrain
AI sommelier for your wine cellar. Transforms Vinocell CSV exports into normalised Parquet tables, per-wine Markdown dossiers, and an in-process DuckDB query layer that AI agents can use via the Model Context Protocol.
Quick start
# Clone and install (Python 3.11+)
git clone https://github.com/urban-buss/cellarbrain.git
cd cellarbrain
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -e .
Usage
1. Run the ETL pipeline
Export your cellar from cellarbrain (File → Export → CSV) and place the files
in raw/:
raw/
├── export-wines.csv
├── export-bottles-stored.csv
└── export-bottles-gone.csv # optional
Then run:
# Full load (first time)
cellarbrain etl raw/export-wines.csv raw/export-bottles-stored.csv raw/export-bottles-gone.csv -o output
# Incremental sync (subsequent runs — detects changes, preserves IDs)
cellarbrain etl raw/export-wines.csv raw/export-bottles-stored.csv raw/export-bottles-gone.csv -o output --sync
Output goes to output/ — 12 Parquet entity files and per-wine Markdown
dossiers under output/wines/.
2. Query your cellar
# SQL query (DuckDB syntax)
cellarbrain query "SELECT w.name, wy.name AS winery, w.vintage FROM wine w JOIN winery wy ON w.winery_id = wy.winery_id LIMIT 10"
# Output as CSV or JSON
cellarbrain query "SELECT * FROM wine LIMIT 5" --format csv
cellarbrain query "SELECT * FROM bottle WHERE status = 'stored'" --format json
# SQL from a file
cellarbrain query -f my_query.sql
3. Cellar statistics
cellarbrain stats # Overall summary
cellarbrain stats --by country # Grouped by country
cellarbrain stats --by grape # Grouped by grape variety
# Also: region, category, vintage, winery, cellar, provider, status
4. Wine dossiers
cellarbrain dossier 42 # Read dossier for wine #42
cellarbrain dossier --search Barolo # Search wines by name, grape, region…
cellarbrain dossier --pending # Wines with pending agent research
5. Validate output
cellarbrain validate # Check Parquet integrity
6. Start the MCP server
cellarbrain mcp # stdio transport (default)
cellarbrain mcp --transport sse # SSE transport for HTTP clients
All subcommands accept -d <path> to point at a different data directory
(default: output).
Legacy mode: The old
cellarbrain <wines.csv> <bottles.csv>syntax still works but emits a deprecation warning.
Web Explorer
A local web dashboard for browsing your cellar, observability data, and running queries interactively.
cellarbrain dashboard # opens at http://localhost:8017
Pages: overview, tool usage, errors, sessions, latency charts, live tail (SSE), cellar browser, bottles, drinking window, tracked wines, SQL playground, statistics, and workbench. Requires a prior ETL run and MCP log store.
MCP server
The MCP server exposes 7 read/write tools for AI agents (Claude, OpenClaw, Copilot, etc.). Tools are thin data primitives — all reasoning stays in the agent.
Tools
| Tool | Description |
|---|---|
query_cellar |
Run read-only SQL against the cellar (DuckDB over Parquet) |
cellar_stats |
Summary statistics, optionally grouped by 9 dimensions |
find_wine |
Text search across name, winery, region, grape, vintage |
read_dossier |
Read a wine's full Markdown dossier |
update_dossier |
Write to agent-owned dossier sections (ETL sections protected) |
reload_data |
Re-run the ETL pipeline in-process |
pending_research |
List wines with empty agent sections, sorted by priority |
Resources
| URI | Description |
|---|---|
wine://list |
All wines with basic metadata |
wine://cellar |
Wines currently in the cellar |
wine://favorites |
Favorite wines |
wine://{wine_id} |
Full dossier for a specific wine |
cellar://stats |
Current cellar statistics |
cellar://drinking-now |
Wines in their optimal drinking window |
etl://last-run |
Last ETL run metadata |
etl://changes |
Change log from the last ETL run |
Prompts
| Prompt | Description |
|---|---|
cellar_qa |
System prompt for cellar Q&A (embeds live stats) |
food_pairing |
Food pairing workflow for a given dish |
wine_research |
Deep research workflow for a single wine |
batch_research |
Batch research across pending wines |
Configure with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"cellarbrain": {
"command": "cellarbrain",
"args": ["mcp"],
"env": {}
}
}
}
If cellarbrain is installed in a virtualenv, use the full path:
{
"mcpServers": {
"cellarbrain": {
"command": "/path/to/cellarbrain/.venv/bin/cellarbrain",
"args": ["mcp"],
"env": {}
}
}
}
To point at a different data directory:
{
"mcpServers": {
"cellarbrain": {
"command": "cellarbrain",
"args": ["-d", "/path/to/output", "mcp"],
"env": {}
}
}
}
Configure with VS Code (Copilot)
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"cellarbrain": {
"command": "cellarbrain",
"args": ["mcp"],
"env": {}
}
}
}
Or with a virtualenv on Windows:
{
"servers": {
"cellarbrain": {
"command": ".venv\\Scripts\\cellarbrain.exe",
"args": ["-d", "output", "mcp"],
"env": {}
}
}
}
Configure with OpenClaw
See .docs/design/openclaw-skill.md for
the full skill integration design.
Optional OpenClaw iMessage notifications
Cellarbrain can ask OpenClaw to send a short iMessage after each successful ETL, including runs with no detected changes. When notifications are enabled, failed ETL runs also send a best-effort failure alert. Notifications are disabled by default.
Add this to your local cellarbrain.toml (keep personal recipient details out of shared config files):
[notifications]
enabled = true
target = "+417XXXXXXXX" # replace with your iMessage number in international format
# command = "openclaw" # or an absolute path if launchd cannot find it
# timeout_seconds = 15
# strict = false # success-alert delivery failure does not fail ETL
The recipient is passed to OpenClaw's documented openclaw message send --channel imessage command. OpenClaw and its iMessage channel must already be configured on the local Mac. Cellarbrain uses a shell-free subprocess call and does not expose the Gateway. Successful sends are recorded in .cellarbrain-notifications.json inside the ETL output directory to suppress duplicate sends for the same run. Failure messages contain no exception text or source data.
To verify the local OpenClaw/iMessage setup independently of ETL, run:
cellarbrain notifications test
This sends a real test message using the configured target and command, even if automatic notifications are disabled. It prints OpenClaw's captured stdout/stderr and retries, and exits with status 1 on failure. You can supply --target and --message to override the configured target and default test text. Manual tests do not write ETL delivery state.
Data model
The ETL produces 12 normalised Parquet tables:
| Table | Description |
|---|---|
wine |
Central wine catalog with all attributes |
bottle |
Individual bottles (stored + consumed) |
winery |
Producer lookup |
appellation |
Country / region / subregion / classification |
grape |
Grape variety lookup |
wine_grape |
Wine–grape junction with blend percentages |
tasting |
Personal tasting notes and scores |
pro_rating |
Professional critic scores |
cellar |
Physical storage locations |
provider |
Retailers / sources |
etl_run |
Pipeline run history |
change_log |
Row-level insert / update / delete audit trail |
Plus per-wine Markdown dossiers in output/wines/ with:
- ETL-owned sections (identity, origin, inventory, tastings, etc.)
- Agent-owned sections (producer profile, vintage report, food pairings, etc.)
- YAML frontmatter tracking which agent sections are populated vs pending
See .docs/data-model/source/ and
.docs/data-model/target/ for detailed field documentation.
Project structure
src/cellarbrain/
├── cli.py # CLI entry point with subcommands
├── reader.py # CSV readers
├── parsers.py # Field-level parsers
├── transform.py # Normalisation and entity building
├── writer.py # Parquet writer with Arrow schemas
├── validate.py # Post-ETL validation
├── incremental.py # Change detection and sync
├── markdown.py # Dossier generation with agent section preservation
├── query.py # DuckDB query layer (stats, search, SQL)
├── dossier_ops.py # Dossier read/write/pending operations
└── mcp_server.py # FastMCP server (7 tools, 8 resources, 4 prompts)
Development
Note: Unit tests and smoke tests require a source checkout of the repository. They are not included in the PyPI package.
# Clone and set up for development
git clone https://github.com/urban-buss/cellarbrain.git
cd cellarbrain
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # macOS / Linux
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run only unit tests (fast, no CSV files needed)
pytest tests/ -v --ignore=tests/test_integration.py
# Run integration tests (requires raw/*.csv files)
pytest tests/test_integration.py -v
License
Private — not for redistribution.
Metadata
Release files for cellarbrain 0.3.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cellarbrain-0.3.8.tar.gz | 1.1 MB | With provenance | Details for cellarbrain-0.3.8.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cellarbrain-0.3.8-py3-none-any.whl | Python 3 | none | any | Details for cellarbrain-0.3.8-py3-none-any.whl |
Total release size: 2.0 MB
Release files / cellarbrain-0.3.8.tar.gz
| Download URL | cellarbrain-0.3.8.tar.gz |
|---|---|
| Size | 1.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f90febe80d7508715223d4a43294280d55ac3b8b05d3847619a52e788ffc3a60
|
|
BLAKE2b-256 checksum How to use checksums |
2ecfc0500977af8ccdf350ba6e81addef285af1195a0fcb7513b0f511524d073
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / cellarbrain-0.3.8-py3-none-any.whl
| Download URL | cellarbrain-0.3.8-py3-none-any.whl |
|---|---|
| Size | 877.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a5c02bcf2ae26a818c1d0cfb89e62f4055790052eb4911c0bedbaaf3a1a0f30f
|
|
BLAKE2b-256 checksum How to use checksums |
e7a369cf2b176509cd7797548f290d5f700ca4409ebb8531a01e2d573e560fde
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for cellarbrain 0.3.8
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for cellarbrain-0.3.8.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.