A content-addressable protocol for universal food data. One axiom. Three fields. Six base types. Every food industry operation. id = SHA-256(canonical(type + state + refs)) The food industry spans 14 sectors — farming, processing, distribution, retail, hospitality, regulation, sustainability, and more. Every sector models food data differently. There is no shared primitive. FoodBlock is that primi
Add this skill
npx mdskills install FoodXDevelopment/foodblockComprehensive food data protocol with natural language parsing, provenance tracking, and federation support
1# FoodBlock23A content-addressable protocol for universal food data.45One axiom. Three fields. Six base types. Every food industry operation.67```json8{9 "type": "substance.product",10 "state": { "name": "Sourdough", "price": 4.50, "allergens": { "gluten": true } },11 "refs": { "seller": "a1b2c3...", "inputs": ["flour_hash", "water_hash", "yeast_hash"] }12}13```1415`id = SHA-256(canonical(type + state + refs))`1617## Why1819The food industry spans 14 sectors — farming, processing, distribution, retail, hospitality, regulation, sustainability, and more. Every sector models food data differently. There is no shared primitive.2021FoodBlock is that primitive. One data structure that can represent a farm harvest, a restaurant menu item, a food safety certification, a cold chain reading, a grocery order, or a consumer review. Same three fields. Same hashing. Same protocol.2223## The Primitive2425Every FoodBlock has exactly three fields:2627| Field | Type | Description |28|-------|------|-------------|29| `type` | string | What kind of block (dot-notated subtypes) |30| `state` | object | The block's data (schemaless, any valid JSON) |31| `refs` | object | Named references to other blocks by hash |3233Identity is derived from content: `SHA-256(canonical(type + state + refs))`. Same content always produces the same hash, regardless of where or when the block is created.3435## Six Base Types3637**Entities** — things that exist:38- **actor** — farmer, restaurant, retailer, regulator, consumer, device39- **place** — farm, factory, store, warehouse, kitchen, vehicle40- **substance** — ingredient, product, meal, surplus, commodity4142**Actions** — things that happen:43- **transform** — cooking, milling, harvesting, fermenting, composting44- **transfer** — sale, shipment, donation, booking, subscription45- **observe** — review, certification, inspection, post, sensor reading4647Subtypes via dot notation: `actor.producer`, `substance.product`, `observe.review`, `transfer.order`.4849## Install5051```bash52npm install foodblock53```5455## Quick Start — `fb()`5657The fastest way to use FoodBlock. Describe food in plain English, get structured blocks back.5859```javascript60const { fb } = require('foodblock')6162fb("Sourdough bread, $4.50, organic, contains gluten")63// => { type: 'substance.product', state: { name: 'Sourdough bread', price: { value: 4.5, unit: 'USD' }, organic: true, allergens: { gluten: true } }, blocks: [...] }6465fb("Amazing pizza at Luigi's, 5 stars")66// => { type: 'observe.review', state: { name: "Luigi's", rating: 5, text: "..." }, blocks: [...] }6768fb("Green Acres Farm, 200 acres, organic wheat in Oregon")69// => { type: 'actor.producer', state: { name: 'Green Acres Farm', acreage: 200, crop: 'organic wheat', region: 'Oregon' }, blocks: [...] }7071fb("Walk-in cooler temperature 4 celsius")72// => { type: 'observe.reading', state: { temperature: { value: 4, unit: 'celsius' } }, blocks: [...] }7374fb("Ordered 50kg flour from Stone Mill")75// => { type: 'transfer.order', state: { weight: { value: 50, unit: 'kg' } }, blocks: [...] }76```7778No types to memorize. No schemas to configure. No API calls — `fb()` is pure pattern matching, runs locally, costs nothing.7980## Programmatic API8182```javascript83const fb = require('foodblock')8485// Create a farm86const farm = fb.create('actor.producer', { name: 'Green Acres Farm' })87// => { hash: 'e3b0c4...', type: 'actor.producer', state: {...}, refs: {} }8889// Create a product with provenance90const wheat = fb.create('substance.ingredient', { name: 'Organic Wheat' }, { source: farm.hash })91const flour = fb.create('substance.product', { name: 'Stoneground Flour' }, { source: wheat.hash })92const bread = fb.create('substance.product', {93 name: 'Sourdough',94 price: 4.5095}, {96 seller: bakery.hash,97 inputs: [flour.hash, water.hash, yeast.hash]98})99100// Update (creates new block, old one preserved)101const updated = fb.update(bread.hash, 'substance.product', {102 name: 'Sourdough',103 price: 5.00104}, { seller: bakery.hash })105// updated.refs.updates === bread.hash106107// Sign and verify108const keys = fb.generateKeypair()109const signed = fb.sign(bread, farm.hash, keys.privateKey)110// signed.protocol_version === '0.4.0'111const valid = fb.verify(signed, keys.publicKey) // true112113// Provenance chain114const history = await fb.chain(updated.hash, resolve)115// [{ price: 5.00 }, { price: 4.50 }] — newest to oldest116117// Validate against schema118const errors = fb.validate(bread) // [] if valid119120// Tombstone (GDPR erasure)121const ts = fb.tombstone(bread.hash, user.hash, { reason: 'gdpr_erasure' })122123// Offline queue124const queue = fb.offlineQueue()125queue.create('transfer.order', { total: 12.00 }, { seller: farmHash })126await queue.sync('https://api.example.com/foodblock')127128// --- Human Interface ---129130// Aliases: use @names instead of hashes131const reg = fb.registry()132const myFarm = reg.create('actor.producer', { name: 'Green Acres' }, {}, { alias: 'farm' })133const myWheat = reg.create('substance.ingredient', { name: 'Wheat' }, { source: '@farm' })134// '@farm' resolves to myFarm.hash automatically135136// FoodBlock Notation: one-line text format137const blocks = fb.parseAll(`138@farm = actor.producer { "name": "Green Acres Farm" }139@wheat = substance.ingredient { "name": "Wheat" } -> source: @farm140`)141142// Explain: human-readable narrative from graph143const story = await fb.explain(bread.hash, resolve)144// "Sourdough ($4.50). By Green Acres Bakery. Made from Organic Flour (Green Acres Farm)."145146// URIs: shareable block references147fb.toURI(bread) // 'fb:a1b2c3...'148fb.toURI(bread, { alias: 'sourdough' }) // 'fb:substance.product/sourdough'149150// --- Templates ---151152// Use built-in templates for common patterns153const chain = fb.fromTemplate(fb.TEMPLATES['supply-chain'], {154 farm: { state: { name: 'Green Acres Farm' } },155 crop: { state: { name: 'Organic Wheat' } },156 processing: { state: { name: 'Stone Milling' } },157 product: { state: { name: 'Flour', price: 3.20 } }158})159// Returns 5 blocks in dependency order, with @alias refs auto-resolved160161// Create custom templates162const myTemplate = fb.createTemplate('Bakery Review', 'Review a bakery product', [163 { type: 'actor.venue', alias: 'bakery', required: ['name'] },164 { type: 'substance.product', alias: 'item', refs: { seller: '@bakery' } },165 { type: 'observe.review', alias: 'review', refs: { subject: '@item' }, required: ['rating'] }166])167168// --- Federation ---169170// Discover another FoodBlock server171const info = await fb.discover('https://farm.example.com')172// { protocol: 'foodblock', version: '0.4.0', types: [...], count: 142 }173174// Resolve blocks across multiple servers175const resolve = fb.federatedResolver([176 'http://localhost:3111',177 'https://farm.example.com',178 'https://market.example.com'179])180const block = await resolve('a1b2c3...') // tries each server in order181```182183## Sandbox184185Try it locally with zero setup:186187```bash188cd sandbox189node server.js190```191192```bash193# List all blocks194curl localhost:3111/blocks195196# Filter by type197curl localhost:3111/blocks?type=substance.product198199# Get head blocks only (latest versions)200curl localhost:3111/blocks?type=substance.product&heads=true201202# Provenance chain203curl localhost:3111/chain/<hash>204205# Create a block206curl -X POST localhost:3111/blocks \207 -H "Content-Type: application/json" \208 -d '{"type":"observe.review","state":{"rating":5,"text":"Amazing"},"refs":{"subject":"<product_hash>"}}'209210# Batch create (offline sync)211curl -X POST localhost:3111/blocks/batch \212 -H "Content-Type: application/json" \213 -d '{"blocks":[...]}'214215# Tombstone (content erasure)216curl -X DELETE localhost:3111/blocks/<hash>217218# Federation discovery219curl localhost:3111/.well-known/foodblock220221# List templates222curl localhost:3111/blocks?type=observe.template223224# Natural language entry point225curl -X POST localhost:3111/fb \226 -H "Content-Type: application/json" \227 -d '{"text":"Sourdough bread, $4.50, organic, contains gluten"}'228229# Forward traversal (what references this block?)230curl localhost:3111/forward/<hash>231232# Natural language → blocks233curl -X POST localhost:3111/fb \234 -H "Content-Type: application/json" \235 -d '{"text":"Sourdough bread, $4.50, organic, contains gluten"}'236237# List vocabularies238curl localhost:3111/blocks?type=observe.vocabulary239```240241The sandbox ships preloaded with 47 blocks modelling a complete bakery supply chain — from farm to consumer, including certifications, shipments, cold chain readings, reviews, and operational vocabularies.242243## API244245### `fb(text) → { blocks, primary, type, state, text }`246247The natural language entry point. Pass any food-related text, get FoodBlocks back. Detects intent (product, review, farm, order, certification, reading, process, venue, ingredient), extracts quantities (price, weight, volume, temperature, rating), flags (organic, gluten-free, kosher, etc.), and relationships ("from X", "at Y", "by Z"). No LLM — pure regex pattern matching against built-in vocabularies.248249### `create(type, state, refs) → block`250251Create a new FoodBlock. Returns `{ hash, type, state, refs }`.252253### `update(previousHash, type, state, refs) → block`254255Create an update block that supersedes a previous version. Automatically adds `refs.updates`.256257### `hash(type, state, refs) → string`258259Compute the SHA-256 hash without creating a block object.260261### `chain(hash, resolve, opts) → block[]`262263Follow the update chain backwards. `resolve` is `async (hash) => block | null`.264265### `tree(hash, resolve, opts) → { block, ancestors }`266267Follow ALL refs recursively to build the full provenance tree.268269### `head(hash, resolveForward) → string`270271Find the latest version in an update chain.272273### `sign(block, authorHash, privateKey) → wrapper`274275Sign a block with Ed25519. Returns `{ foodblock, author_hash, signature, protocol_version }`.276277### `verify(wrapper, publicKey) → boolean`278279Verify a signed block wrapper.280281### `generateKeypair() → { publicKey, privateKey }`282283Generate a new Ed25519 keypair for signing.284285### `encrypt(value, recipientPublicKeys) → envelope`286287Encrypt a value for multiple recipients using envelope encryption (Section 7.2).288289### `decrypt(envelope, privateKey, publicKey) → value`290291Decrypt an encryption envelope.292293### `validate(block, schema?) → string[]`294295Validate a block against its declared schema or a provided schema. Returns an array of error messages (empty = valid).296297### `tombstone(targetHash, requestedBy, opts?) → block`298299Create a tombstone block for content erasure (Section 5.4).300301### `offlineQueue() → Queue`302303Create an offline queue for local-first block creation with batch sync.304305### `query(resolve) → Query`306307Fluent query builder:308309```javascript310const results = await fb.query(resolver)311 .type('substance.product')312 .byRef('seller', bakeryHash)313 .whereLt('price', 10)314 .latest()315 .limit(20)316 .exec()317```318319### `registry() → Registry`320321Alias registry for human-readable references. Use `@name` in refs instead of hashes.322323### `parse(line) → { alias, type, state, refs }`324325Parse a single line of FoodBlock Notation (FBN).326327### `parseAll(text) → block[]`328329Parse multiple lines of FBN.330331### `format(block, opts?) → string`332333Format a block as FBN text.334335### `explain(hash, resolve) → string`336337Generate a human-readable narrative from a block's provenance graph.338339### `toURI(block, opts?) → string`340341Convert a block to a `fb:` URI. `toURI(block)` → `fb:<hash>`, `toURI(block, { alias: 'name' })` → `fb:<type>/<alias>`.342343### `fromURI(uri) → object`344345Parse a `fb:` URI into `{ hash }` or `{ type, alias }`.346347### `createTemplate(name, description, steps, opts?) → block`348349Create a template block (`observe.template`) that defines a reusable workflow pattern.350351### `fromTemplate(template, values) → block[]`352353Instantiate a template into real blocks. `values` maps step aliases to `{ state, refs }` overrides. `@alias` references between steps are resolved automatically.354355### `TEMPLATES`356357Built-in templates: `supply-chain`, `review`, `certification`.358359### `discover(serverUrl, opts?) → info`360361Fetch a server's `/.well-known/foodblock` discovery document.362363### `federatedResolver(servers, opts?) → resolve`364365Create a resolver that tries multiple servers in priority order. Returns `async (hash) => block | null` with optional caching.366367### `createVocabulary(domain, forTypes, fields, opts?) → block`368369Create a vocabulary block (`observe.vocabulary`) defining canonical field names, types, and natural language aliases for a domain.370371### `mapFields(text, vocabulary) → { matched, unmatched }`372373Extract field values from natural language text using a vocabulary's aliases. Returns matched fields and unmatched terms.374375### `VOCABULARIES`376377Built-in vocabulary definitions: `bakery`, `restaurant`, `farm`, `retail`, `lot`, `units`, `workflow`.378379### `quantity(value, unit, type?) → { value, unit }`380381Create a quantity object. Validates unit against the `units` vocabulary if `type` is provided (e.g. `'weight'`, `'volume'`, `'temperature'`).382383### `transition(from, to) → boolean`384385Validate a workflow state transition against the `workflow` vocabulary's transition map (e.g. `draft→order` is valid, `draft→shipped` is not).386387### `nextStatuses(status) → string[]`388389Get valid next statuses for a given workflow status.390391### `localize(block, locale, fallback?) → block`392393Extract locale-specific text from multilingual state fields. Fields using `{ en: "...", fr: "..." }` nested objects are resolved to the requested locale.394395### `forward(hash, resolveForward) → { referencing, count }`396397Find all blocks that reference a given hash. Returns blocks grouped by ref role.398399### `recall(sourceHash, resolveForward, opts?) → { affected, depth, paths }`400401Trace contamination/recall paths downstream via BFS. Starting from a source block, follows all forward references recursively. Supports `types` and `roles` filters.402403### `downstream(ingredientHash, resolveForward) → block[]`404405Find all downstream substance blocks that use a given ingredient (convenience wrapper around `recall`).406407### `merkleize(state) → { root, leaves, tree }`408409Build a Merkle tree from a state object for selective disclosure.410411### `selectiveDisclose(state, fieldNames) → { disclosed, proof, root }`412413Reveal only specific fields with a Merkle proof that they belong to the block.414415### `verifyProof(disclosed, proof, root) → boolean`416417Verify a selective disclosure proof.418419### `merge(hashA, hashB, resolve, opts?) → block`420421Create a merge block resolving a fork between two update chain heads.422423### `attest(targetHash, attestorHash, opts?) → block`424425Create an attestation block confirming a claim. `opts.confidence`: `verified`, `probable`, `unverified`.426427### `dispute(targetHash, disputerHash, reason) → block`428429Create a dispute block challenging a claim.430431### `trustScore(hash, allBlocks) → number`432433Compute net trust score: attestations minus disputes.434435### `createSnapshot(blocks, opts?) → block`436437Summarize a set of blocks into a snapshot with a Merkle root for archival verification.438439## The Axiom440441**A FoodBlock's identity is its content:** `SHA-256(canonical(type + state + refs))`.442443Everything follows from this:444- **Immutability** — change content, change identity445- **Determinism** — same content, same hash, anywhere446- **Deduplication** — identical products resolve to one block447- **Tamper evidence** — any modification is detectable448- **Offline validity** — no server needed to create blocks449- **Provenance** — refs form a directed graph of history450451Seven operational rules govern the protocol's use:4524531. A FoodBlock has exactly three fields: `type`, `state`, `refs`.4542. Authentication: `{ foodblock, author_hash, signature, protocol_version }` using Ed25519.4553. Encrypted state: `_` prefixed keys contain envelope-encrypted values.4564. Author-scoped updates: only the original author or approved actor may create successors.4575. Tombstones erase content while preserving graph structure.4586. Schema declarations are optional.4597. The protocol is open. No permission required.460461## Canonical JSON462463Deterministic hashing requires deterministic serialization. Aligns with [RFC 8785 (JSON Canonicalization Scheme)](https://tools.ietf.org/html/rfc8785) for number formatting and key ordering:464465- Keys sorted lexicographically at every nesting level466- No whitespace between tokens467- Numbers: no trailing zeros, no leading zeros. `-0` normalized to `0`.468- Strings: Unicode NFC normalization469- Arrays in `refs`: sorted lexicographically (set semantics)470- Arrays in `state`: preserve declared order (sequence semantics)471- Null values: omitted472- Booleans: `true` or `false`473474## Database Schema475476```sql477CREATE TABLE foodblocks (478 hash VARCHAR(64) PRIMARY KEY,479 type VARCHAR(100) NOT NULL,480 state JSONB NOT NULL DEFAULT '{}',481 refs JSONB NOT NULL DEFAULT '{}',482 author_hash VARCHAR(64),483 signature TEXT,484 protocol_version VARCHAR(10) DEFAULT '0.3',485 chain_id VARCHAR(64),486 is_head BOOLEAN DEFAULT TRUE,487 created_at TIMESTAMP DEFAULT NOW()488);489```490491Full schema with indexes, author-scoped head trigger, and tombstone trigger: [`sql/schema.sql`](sql/schema.sql)492493## Cross-Language Test Vectors494495[`test/vectors.json`](test/vectors.json) contains 30 known inputs and expected hashes — including tombstone blocks, schema references, vocabulary blocks, attestation blocks, merge blocks, RFC 8785 number edge cases, and more. Any SDK in any language must produce identical hashes for these inputs. If JavaScript and Python disagree, the protocol is broken.496497## Project Structure498499```500foodblock/501├── spec/whitepaper.md Protocol specification (v0.4)502├── sdk/javascript/ JavaScript SDK (reference implementation)503│ ├── src/ block, chain, verify, encrypt, validate, offline, tombstone,504│ │ alias, notation, explain, uri, template, federation,505│ │ vocabulary, forward, merge, merkle, snapshot, attestation506│ └── test/ Test suite (104 tests)507├── sdk/python/ Python SDK508│ ├── foodblock/ block, chain, verify, validate, tombstone,509│ │ alias, notation, explain, uri, template, federation,510│ │ vocabulary, forward, merge, merkle, snapshot, attestation511│ └── tests/ Test suite (80 tests)512├── sdk/go/ Go SDK513│ └── foodblock.go block, chain, sign/verify, tombstone514├── sdk/swift/ Swift SDK515│ └── Sources/ block, tombstone516├── mcp/ MCP server for AI agent integration (15 tools)517├── sandbox/ Local sandbox server518│ ├── server.js Zero-dependency HTTP API + federation discovery519│ └── seed.js 47-block bakery chain + templates + vocabularies520├── sql/schema.sql Postgres schema + triggers521├── test/vectors.json Cross-language test vectors (30 vectors)522└── LICENSE MIT523```524525## Sector Coverage526527The six base types cover all fourteen food industry sectors:528529| Sector | Key Types |530|--------|-----------|531| Primary Production | `actor.producer`, `place.farm`, `transform.harvest` |532| Processing | `actor.maker`, `transform.process`, `observe.inspection` |533| Distribution | `actor.distributor`, `transfer.shipment`, `observe.reading` |534| Retail | `substance.product`, `transfer.order` |535| Hospitality | `actor.venue`, `transfer.booking`, `observe.review` |536| Food Service | `observe.plan`, `transform.process` |537| Waste & Sustainability | `actor.sustainer`, `substance.surplus`, `transfer.donation` |538| Regulation | `actor.authority`, `observe.certification` |539| Education & Media | `actor.creator`, `observe.post` |540| Community | `actor.group`, `observe.event` |541| Health & Nutrition | `actor.professional`, `observe.assessment` |542| Finance | `transfer.investment`, `observe.market` |543| Cultural Food | `observe.certification`, `place.region` |544| Food Technology | `actor.innovator`, `observe.experiment` |545546## License547548MIT — use it however you want.549550## Links551552- [Whitepaper](spec/whitepaper.md) ([PDF](spec/whitepaper.pdf))553- [Technical Specification](spec/technical-whitepaper.md) ([PDF](spec/technical-whitepaper.pdf))554- [Test Vectors](test/vectors.json)555- [Schema](sql/schema.sql)556- [MCP Server](mcp/README.md)557
Full transparency — inspect the skill content before installing.