pantrybase 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "pantrybase",
3
+ "owner": { "name": "Ryan Dick" },
4
+ "description": "Local-first recipe knowledge base plugin for Claude Code.",
5
+ "plugins": [
6
+ {
7
+ "name": "pantrybase",
8
+ "source": "./",
9
+ "description": "Capture recipe cards from photos, search and match recipes to your pantry, and synthesize new ones."
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "pantrybase",
3
+ "displayName": "Pantrybase",
4
+ "version": "0.1.0",
5
+ "description": "Local-first recipe knowledge base for Claude Code: capture meal-box recipe cards from photos, search by ingredient, tag, allergen or mood, match recipes to your pantry, and synthesize new recipes. SQLite FTS5 + vector search, markdown recipes as the source of truth.",
6
+ "author": {
7
+ "name": "Ryan Dick"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": ["recipes", "pantry", "meal-kit", "knowledge-graph", "search"],
11
+ "mcpServers": {
12
+ "pantrybase": {
13
+ "command": "${CLAUDE_PLUGIN_ROOT}/bin/pb-server",
14
+ "args": [],
15
+ "env": {
16
+ "PANTRYBASE_PLUGIN_ROOT": "${CLAUDE_PLUGIN_ROOT}",
17
+ "PANTRYBASE_PROJECT_ROOT": "${CLAUDE_PROJECT_DIR}"
18
+ }
19
+ }
20
+ }
21
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryan Dick
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,154 @@
1
- # Temporary Holding Version
1
+ # pantrybase
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A local-first recipe knowledge base for [Claude Code](https://claude.com/claude-code). Photograph your meal-box recipe cards, let Claude read them into structured recipes, then search by ingredient, tag, allergen or mood, see what you can cook with what's in your pantry, explore the collection as a graph, and invent new recipes grounded in the ones you already have.
4
+
5
+ - **Capture from photos** — drop card photos (front and back, iPhone HEIC included) into an inbox; Claude pairs them, extracts the full recipe (ingredients with prep notes, steps, timings, nutrition, allergens, chef, wine pairing…), tags it against a controlled vocabulary and saves it. Retakes and duplicates are caught.
6
+ - **Find anything** — hybrid keyword + semantic search (SQLite FTS5 + local vector embeddings), with facets for cuisine, diet, dish, protein, flavour, texture, technique, equipment and allergens to leave out.
7
+ - **What can I cook?** — keep a pantry inventory; recipes are ranked by how much of them you have, ignoring staples, with near misses called out.
8
+ - **New recipes** — Claude draws on related recipes and shared ingredient patterns to write new ones, saved with links to their sources.
9
+ - **Your data stays yours** — recipes are plain markdown files in your project; the database is a rebuildable index. No API keys, no cloud: the only download is a 34 MB embedding model.
10
+
11
+ ## Requirements
12
+
13
+ - Node.js 22.12 or newer
14
+ - Claude Code (`claude` on your PATH)
15
+ - HEIC photos: macOS converts them natively; elsewhere the optional `heic-convert` dependency is used
16
+
17
+ ## Install
18
+
19
+ ```sh
20
+ npx pantrybase install
21
+ ```
22
+
23
+ This installs a stable copy into `~/.pantrybase/plugin` with its native dependencies, checks that SQLite, the vector extension and the image library load, downloads the embedding model, and registers the plugin with Claude Code at user scope. Start a new Claude Code session (or run `/reload-plugins`) afterwards. Re-run the command to update.
24
+
25
+ ```sh
26
+ npx pantrybase doctor # check everything is wired up
27
+ npx pantrybase uninstall # remove the plugin (your recipes are never touched)
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ 1. **Add photos.** Drop card photos into `pantrybase/inbox/` in your project, upload them in the web UI, or ask Claude: *"import the recipe photos in ~/Pictures/ucook"*.
33
+ 2. **Ingest.** Run `/pantrybase:ingest`. Claude works through the queue card by card; it can stop and resume at any time.
34
+ 3. **Cook.** Ask *"what can I make with what's in my pantry?"*, *"something cosy and vegetarian under 30 minutes"*, or *"invent a new curry from my favourites"* — or run `/pantrybase:cook`.
35
+ 4. **Browse.** Ask Claude to open the web UI, or run `npx pantrybase ui --open`.
36
+
37
+ ## Where your data lives
38
+
39
+ Everything lives in a `pantrybase/` folder in the project Claude Code is working in:
40
+
41
+ ```
42
+ pantrybase/
43
+ recipes/<slug>.md the recipes — the source of truth
44
+ images/<slug>/ each recipe's card photos (front.jpg, back.jpg)
45
+ inbox/ photos waiting to be read (skipped/ and failed/ keep a reason file)
46
+ ingredients.yaml ingredient catalog: canonical names, aliases, staples
47
+ vocabulary.yaml tag vocabulary: allowed values, synonyms, cuisine hierarchy
48
+ providers/ optional meal-box provider profiles of your own
49
+ pantrybase.db search index (safe to delete; rebuilt from the files)
50
+ ```
51
+
52
+ Recipe files are markdown with YAML frontmatter, so they diff cleanly, survive anything, and can be edited by hand — edits are picked up on the next tool call. Commit the folder (minus `pantrybase.db`) to keep your collection in git.
53
+
54
+ ```yaml
55
+ ---
56
+ pb: 2
57
+ title: Cosy Potatoes & Crispy Cannellini Beans
58
+ subtitle: with spinach & piquanté peppers
59
+ blurb: Harissa-crisped baby potatoes and roasted cannellini beans on lemony spinach…
60
+ servings: 2
61
+ time: {active: 25, total: 45}
62
+ provider: {id: ucook, plan: Veggie, chef: Kate Gomba, wine: {producer: Neil Ellis Wines, …}}
63
+ tags:
64
+ cuisine: [north-african]
65
+ dish: [traybake]
66
+ allergens: [allium, sulphites, tree-nuts]
67
+ nutrition: {basis: per_100g, energy_kcal: 79, protein_g: 2.6, …}
68
+ ingredients:
69
+ - {raw: 500g Baby Potatoes, canonical: potato, qty: 500, unit: g, prep: rinse & halve, source: box}
70
+ steps:
71
+ - {title: Off you go!, text: Preheat the oven to 200°C…, techniques: [roast], temp_c: 200, minutes: [25, 30]}
72
+ ---
73
+ ```
74
+
75
+ ## Claude Code tools
76
+
77
+ | Tool | What it does |
78
+ |---|---|
79
+ | `pb_search` | Hybrid keyword + semantic search with tag, allergen, time and review filters |
80
+ | `pb_get_recipe` | One recipe, compact or full |
81
+ | `pb_pantry_match` | Recipes ranked by pantry coverage, with what's missing |
82
+ | `pb_synthesis_context` | Source recipes and shared patterns for inventing a new recipe |
83
+ | `pb_list_tags` | Tags and facets in use, plus the vocabulary |
84
+ | `pb_pantry_list` / `_add` / `_remove` | Manage the pantry |
85
+ | `pb_providers` | Meal-box provider profiles and their extraction guides |
86
+ | `pb_ingest_source` | Copy photos from files or folders into the inbox |
87
+ | `pb_inbox_next` / `_image` / `_resolve` / `_list` | Work through the photo queue |
88
+ | `pb_save_recipe` | Save or update a recipe (and archive its photos) |
89
+ | `pb_open_ui` | Start the web UI and get its URL |
90
+ | `pb_merge_ingredients` | Merge two ingredient names everywhere |
91
+ | `pb_stats` / `pb_rebuild` | Counts and paths; re-sync the index from the files |
92
+
93
+ Skills: `/pantrybase:ingest` (capture cards) and `/pantrybase:cook` (find, match, invent).
94
+
95
+ ## Web UI
96
+
97
+ `npx pantrybase ui` (or the `pb_open_ui` tool) serves a UI on `http://127.0.0.1:7433`:
98
+
99
+ - **Recipes** — search with facets; recipe pages with photos, pantry ticks, steps, nutrition, allergens and lineage
100
+ - **Pantry** — your inventory and *what can I cook*
101
+ - **Graph** — recipes, ingredients and tags as a navigable network
102
+ - **Inbox** — drag-and-drop photo upload and the extraction queue
103
+ - **Tags** — the whole vocabulary at a glance
104
+
105
+ It only listens on localhost and rejects cross-site requests.
106
+
107
+ ## Meal-box providers
108
+
109
+ Provider support is modular. [UCOOK](https://ucook.co.za) (South Africa) ships built in, with a `generic` profile for anything else. A provider is a folder with two files:
110
+
111
+ - `profile.yaml` — how to recognise its cards, which side is which, plan labels → tags (`Veggie` → `diet: vegetarian`), allergen wording, brand names to strip from ingredient names, kitchen items that are really equipment, nutrition basis, regional ingredient names
112
+ - `guide.md` — instructions Claude follows when reading that provider's cards
113
+
114
+ Put your own in `pantrybase/providers/<id>/` (or contribute it to `providers/` here). See [`providers/ucook/`](providers/ucook) for a complete example.
115
+
116
+ ## Vocabulary and catalog
117
+
118
+ Tags are normalised against `pantrybase/vocabulary.yaml`: closed categories (diet, dish, meal, method, time, season, allergen) only accept listed values, open ones (cuisine, flavour, protein…) grow as you go, synonyms map card wording onto one value, and cuisines form a hierarchy so filtering on *asian* finds *thai*. Ingredient names resolve through `pantrybase/ingredients.yaml` (aliases, plurals, regional names; staples never count against pantry coverage). Edit either file and the next tool call re-indexes your recipes.
119
+
120
+ ## How search works
121
+
122
+ Each recipe is indexed as four chunks — title and tags, description and blurb, ingredients, method — in two SQLite FTS5 indexes (stemmed words and trigrams, for typos) and a `sqlite-vec` vector table embedded locally with `bge-small-en-v1.5`. Results are fused with weighted reciprocal-rank fusion, then filtered by tags, allergens and time. The graph is derived from the same tables.
123
+
124
+ ## CLI
125
+
126
+ ```
127
+ pantrybase install | uninstall | doctor
128
+ pantrybase ui [--port N] [--open]
129
+ pantrybase rebuild [--full] [--reembed]
130
+ pantrybase search <query…>
131
+ pantrybase embed | stats | version
132
+ ```
133
+
134
+ ## Development
135
+
136
+ ```sh
137
+ npm install
138
+ npm run build # server (tsup) + web UI (vite)
139
+ npm run check # biome + typecheck + vitest
140
+ npm run dev # watch the server, Vite dev server on :5173
141
+ node dist/cli.js install # install the plugin from your checkout
142
+ ```
143
+
144
+ The code is TypeScript (ESM, Node 22+): `src/storage` (the `StorageAdapter` interface and its SQLite implementation), `src/recipes` (schema, provider rules and vocabulary, save pipeline), `src/ingest` (photo queue), `src/search`, `src/pantry`, `src/synthesis`, `src/graph`, `src/mcp/tools` (one file per tool), `src/web` (HTTP server) and `web/` (Preact app).
145
+
146
+ ### Releases
147
+
148
+ Every merge to `main` publishes a new version to npm automatically (`.github/workflows/release.yml`): the workflow runs the full checks, picks the version from the commits since the last tag (breaking change → major, minor while 0.x · `feat:` → minor · anything else → patch), commits `chore(release): vX.Y.Z` with `package.json` and `.claude-plugin/plugin.json` in sync, tags it, publishes with npm provenance and creates a GitHub release. Pull requests run the CI matrix (Linux and macOS, Node 22 and 24) in `.github/workflows/ci.yml`.
149
+
150
+ One-time setup for publishing — either link the repository as a [trusted publisher](https://docs.npmjs.com/trusted-publishers) for the `pantrybase` package (workflow file `release.yml`), or add an npm automation token as the repository secret `NPM_TOKEN`.
151
+
152
+ ## License
153
+
154
+ MIT
@@ -0,0 +1,38 @@
1
+ # Sourced by the bin/ shims. Sets NODE (node binary) and RUN (package root that has its
2
+ # dependencies installed), following the layout written by `pantrybase install`.
3
+
4
+ PB_HOME="${PANTRYBASE_HOME:-$HOME/.pantrybase}"
5
+
6
+ # Package root: the directory above bin/, wherever this copy lives.
7
+ DIR="$(cd "$(dirname "$PB_SELF")/.." && pwd)"
8
+
9
+ # Node: the binary pinned at install time (so nvm/volta PATH changes never matter), else PATH.
10
+ NODE=""
11
+ if [ -f "$PB_HOME/node-path" ]; then
12
+ NODE="$(cat "$PB_HOME/node-path" 2>/dev/null)"
13
+ fi
14
+ if [ ! -x "$NODE" ]; then
15
+ NODE="$(command -v node 2>/dev/null)"
16
+ fi
17
+
18
+ # Native dependencies live either inside the package (dev checkout, npm -g) or beside it
19
+ # (stable copy inside ~/.pantrybase/plugin/node_modules).
20
+ pb_runnable() {
21
+ [ -f "$1/dist/server.js" ] && { [ -e "$1/node_modules/better-sqlite3/package.json" ] || [ -e "$1/../better-sqlite3/package.json" ]; }
22
+ }
23
+
24
+ RUN="$DIR"
25
+ if ! pb_runnable "$DIR"; then
26
+ RUN=""
27
+ if [ -f "$PB_HOME/root-path" ]; then
28
+ ALT="$(cat "$PB_HOME/root-path" 2>/dev/null)"
29
+ if [ -n "$ALT" ] && pb_runnable "$ALT"; then
30
+ RUN="$ALT"
31
+ fi
32
+ fi
33
+ fi
34
+
35
+ if [ -z "$NODE_COMPILE_CACHE" ]; then
36
+ NODE_COMPILE_CACHE="$PB_HOME/compile-cache"
37
+ export NODE_COMPILE_CACHE
38
+ fi
package/bin/pantrybase ADDED
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+ # CLI shim. Follows symlinks (npm link, npm -g, npx) to find the real package root.
3
+ PB_SELF="$0"
4
+ while [ -L "$PB_SELF" ]; do
5
+ PB_LINK="$(readlink "$PB_SELF")"
6
+ case "$PB_LINK" in
7
+ /*) PB_SELF="$PB_LINK" ;;
8
+ *) PB_SELF="$(dirname "$PB_SELF")/$PB_LINK" ;;
9
+ esac
10
+ done
11
+ . "$(dirname "$PB_SELF")/_resolve.sh"
12
+ if [ ! -x "$NODE" ]; then
13
+ echo "pantrybase: node >= 22.12 is required" >&2
14
+ exit 1
15
+ fi
16
+ if [ -z "$RUN" ]; then
17
+ # Not installed yet and no deps beside this copy: run from here anyway (npx installs deps).
18
+ RUN="$DIR"
19
+ fi
20
+ exec "$NODE" "$RUN/dist/cli.js" "$@"
package/bin/pb-server ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+ # MCP server shim (stdio). Claude Code starts this from the plugin; it must never write to stdout.
3
+ PB_SELF="$0"
4
+ . "$(dirname "$0")/_resolve.sh"
5
+ if [ ! -x "$NODE" ]; then
6
+ echo "pantrybase: no node binary found (run: npx pantrybase install)" >&2
7
+ exit 1
8
+ fi
9
+ if [ -z "$RUN" ]; then
10
+ echo "pantrybase: $DIR has no dependencies installed and no stable copy is pinned in $PB_HOME/root-path (run: npx pantrybase install)" >&2
11
+ exit 1
12
+ fi
13
+ exec "$NODE" "$RUN/dist/server.js" "$@"