DEV Community

Cover image for We Open-Sourced a Protocol to Fix How the Food Supply Chain Talks to Itself
Djowda for Djowda

Posted on • Originally published at djowda.com

We Open-Sourced a Protocol to Fix How the Food Supply Chain Talks to Itself

Almost one billion people face food insecurity every year — not because the world doesn't produce enough food, but because the coordination infrastructure between producers and consumers is broken.

Farmers don't know who needs what. Stores don't know what's available 2km away. Surplus rots while scarcity persists — sometimes in the same city block.

We spent years building a prototype to solve this. Today we're publishing the protocol that powers it.

👉 djowda.com/difp — DIFP v0.1, Provisional Specification · CC-BY 4.0 · Free to implement


What DIFP actually is

DIFP (Djowda Interconnected Food Protocol) is a lightweight, open, spatial food coordination protocol. It defines:

  • Participant identity — how food ecosystem actors identify themselves globally without a central registry
  • Spatial addressing — how Earth's surface is divided into ~500m × 500m cells, each acting as a coordination zone
  • Presence & discovery — how participants announce and find each other within and across cells
  • The trade message format — a universal structure for orders, asks, and donations between any two participants
  • Protocol federation — how independent DIFP nodes interoperate without a central broker

It is transport-agnostic. The reference implementation uses Firebase Realtime Database. Conformant implementations may use REST, WebSockets, MQTT, or anything equivalent.


The problem it solves for developers

Right now if you're building a grocery delivery app, a farm management tool, a restaurant POS, or a truck routing system — you're building in isolation.

There's no shared layer. No common identity. No standard way to say "I'm a farmer at this location with these items available." Every integration is custom. Every partnership is a new API contract.

DIFP proposes a fix: one protocol, one grid, one trade message format.

Any two systems that implement DIFP can discover each other, exchange availability data, and complete trades — with zero custom integration work.


The spatial grid — the core innovation

The foundational piece of DIFP is a deterministic global grid called MinMax99.

The entire surface of Earth is divided into ~3.44 billion cells, each 500×500 meters. Every participant gets a cell ID derived from their GPS coordinates using a single pure-math function:

public static long geoToCellNumber(double latitude, double longitude) {

    // Longitude → x in meters (linear)
    double x = (longitude + 180.0) * (EARTH_WIDTH_METERS / 360.0);

    // Latitude → y in meters (Mercator, origin at top)
    double y = (EARTH_HEIGHT_METERS / 2.0)
             - Math.log(Math.tan(Math.PI / 4.0 + Math.toRadians(latitude) / 2.0))
               * (EARTH_HEIGHT_METERS / (2.0 * Math.PI));

    // Meters → cell indices
    int xCell = (int) Math.floor(x / CELL_SIZE_METERS);  // CELL_SIZE_METERS = 500
    int yCell = (int) Math.floor(y / CELL_SIZE_METERS);

    // Clamp + encode
    xCell = Math.max(0, Math.min(xCell, NUM_COLUMNS - 1));  // NUM_COLUMNS = 82,000
    yCell = Math.max(0, Math.min(yCell, NUM_ROWS    - 1));  // NUM_ROWS    = 42,000

    return (long) xCell * NUM_ROWS + yCell;
}
Enter fullscreen mode Exit fullscreen mode

Grid constants (all conformant implementations MUST use these exactly):

EARTH_WIDTH_METERS  = 40,075,000
EARTH_HEIGHT_METERS = 20,000,000
CELL_SIZE_METERS    = 500
NUM_COLUMNS         = 82,000
NUM_ROWS            = 42,000
TOTAL_CELLS         ≈ 3.44 billion
Enter fullscreen mode Exit fullscreen mode

Reference test vectors to validate your port:

Location lat, lng Cell ID
Algiers, Algeria 36.7372, 3.0868 3440210
Paris, France 48.8566, 2.3522 3467891
Tokyo, Japan 35.6762, 139.6503 6543210
New York, USA 40.7128, -74.0060 1823445

Why a grid instead of geo-queries?

  • Discovery is O(1). To find all stores near a farmer, query the farmer's cell + immediate neighbors. No radius search. No expensive geo API call.
  • Cells are lobbies. All components in the same cell share context — they can discover each other without knowing each other in advance.
  • Works offline. Cell IDs are computed client-side from GPS. No server round-trip needed to know your own address.
  • Cheap at scale. A Firebase equalTo(cellId) query is fast and inexpensive. No PostGIS, no Elasticsearch geo-shape queries.

Neighbor resolution

def get_nearby_cells(center_cell_id, radius):
    xC, yC = cell_number_to_xy(center_cell_id)
    result = []
    for dx in range(-radius, radius + 1):
        for dy in range(-radius, radius + 1):
            x = clamp(xC + dx, 0, NUM_COLUMNS - 1)
            y = clamp(yC + dy, 0, NUM_ROWS - 1)
            result.append(x * NUM_ROWS + y)
    return result
Enter fullscreen mode Exit fullscreen mode
Radius Grid Cells Coverage
0 1×1 1 ~0.25 km²
1 3×3 9 ~2.25 km²
2 5×5 25 ~6.25 km²
5 11×11 121 ~30 km²

Participant identity — DIDs without a blockchain

DIFP uses a Decentralized Identifier (DID) scheme that requires no central authority and works offline:

difp://{cellId}/{typeCode}/{componentId}

# Examples
difp://3440210/f/ali-farm-01       # Farmer in cell 3,440,210 (Algiers)
difp://3440210/s/safeway-dz-042    # Store in same cell
difp://1820044/fa/cevital-plant-1  # Factory in cell 1,820,044
Enter fullscreen mode Exit fullscreen mode

Ten canonical component types:

Code Actor
sp Seed Provider
f Farmer
fa Factory
w Wholesaler
s Store
r Restaurant
u User / Consumer
t Transport
d Delivery
a Admin

The trade message — one format for everything

All exchanges in the food ecosystem — commercial orders, donation offers, resource requests — are modeled as Trades between exactly two participants.

Three trade types:

Code Type Description
o Order Purchase request with items, quantities, prices
a Ask Demand signal — "I need this, who has it?"
d Donation Surplus signal — "I have this, who needs it?"

The Ask and Donation types are first-class citizens of the protocol, not afterthoughts. They're how DIFP addresses food insecurity directly — signaling surplus and scarcity without requiring a commercial transaction.

Trade message schema

{
  "sId": "difp://3440210/f/ali-farm-01",
  "sT":  "f",
  "sC":  "3440210",
  "rId": "difp://3440210/s/safeway-dz-042",
  "rT":  "s",
  "rC":  "3440210",
  "ty":  "o",
  "st":  "p",
  "items": {
    "difp:item:dz:vegetables:tomato_kg:v1": { "q": 50, "p": 80, "u": "kg" }
  },
  "total":     4000,
  "listSize":  1,
  "createdAt": 1710000000000,
  "info": { "phone": "+213...", "address": "...", "comment": "" }
}
Enter fullscreen mode Exit fullscreen mode

Status lifecycle

PENDING (p)
    │
    ├── receiver accepts ──► ACCEPTED (a)
    │                              │
    │                              └──► PROCESSING (pr) ──► COMPLETED (c) ✓
    │
    ├── receiver denies ──► DENIED (dn) ✗
    │
    └── sender cancels  ──► CANCELLED (x) ✗
Enter fullscreen mode Exit fullscreen mode

The four-node atomic write pattern (fan-out)

Every trade touches four Firebase nodes in a single atomic updateChildren() call. No partial writes. No race conditions.

TD/{tradeId}                                    ← canonical full record
T/{senderType}/{senderId}/o/{tradeId}           ← sender outbox summary
T/{receiverType}/{receiverId}/i/{tradeId}       ← receiver inbox summary
TA/{tradeId}                                    ← analytics (no PII)
Enter fullscreen mode Exit fullscreen mode
Map<String, Object> updates = new HashMap<>();
updates.put("TD/" + tradeId, tradeData);
updates.put("T/" + senderType + "/" + senderId + "/o/" + tradeId, senderSummary);
updates.put("T/" + receiverType + "/" + receiverId + "/i/" + tradeId, receiverSummary);
updates.put("TA/" + tradeId + "/createdAt", timestamp);
updates.put("TA/" + tradeId + "/senderCell", senderCell);
updates.put("TA/" + tradeId + "/receiverCell", receiverCell);

db.updateChildren(updates); // atomic
Enter fullscreen mode Exit fullscreen mode

The TA (analytics) node tracks timing and cell pairs for map-route animation — and must never contain PII (no phone numbers, no addresses, no item details).


The catalog system — PAD + live sync

DIFP separates item metadata (static) from availability and pricing (live).

  • PAD (Pre-loaded Application Data): ~6,000 items per country per component type, distributed as a compressed package with the app. Contains item names (multilingual), categories, units, thumbnail references. Never changes at runtime.
  • Live sync: Only price and available travel over the wire during normal usage.

This means a farmer's app works in a village with 2G. The catalog is already on-device. Only the delta syncs.

Item identity is globally namespaced:

difp:item:{countryCode}:{category}:{itemSlug}:{version}

# Examples
difp:item:dz:vegetables:tomato_kg:v1
difp:item:in:grains:basmati_rice_kg:v2
difp:item:fr:dairy:camembert_250g:v1
Enter fullscreen mode Exit fullscreen mode

Protocol federation

DIFP is designed for independent operators — NGOs, national food agencies, regional cooperatives — to run their own nodes and interoperate.

Every conformant node exposes:

GET https://{host}/.well-known/difp/info
# Returns: protocol version, nodeId, cell coverage, federated peers

GET https://{host}/.well-known/difp/cell/{cellId}
# Returns: all PresenceRecords in that cell

POST https://{host}/.well-known/difp/trade/incoming
# Accepts: signed TradeMessage from another DIFP node
Enter fullscreen mode Exit fullscreen mode

A Tunisian cooperative and an Indian marketplace running separate DIFP nodes can discover each other's participants and complete cross-node trades with zero custom integration — because they speak the same protocol.


How to implement (minimum viable node)

Step 1 — Port the grid algorithm. Validate against the reference test vectors above. This is the only piece that MUST be bit-for-bit identical across all implementations.

Step 2 — Stand up a presence store. Any backend (Firebase, PostgreSQL + PostGIS, DynamoDB). Index by cell_id + component_type. Expose the /.well-known/difp/ endpoints.

Step 3 — Implement the trade engine. Four-node write pattern. Role-based status transitions. Atomic writes.

That's a working DIFP node. Steps 4 (catalog) and 5 (federation) can be added incrementally.

A working node with 10 participants is more valuable than a perfect spec with zero.


What this means for AI + food

One thing we didn't anticipate when designing this: DIFP makes food data natively queryable by AI systems.

Because every participant has a DID, a cell ID, a typed presence record, and a live catalog — any AI assistant with access to a DIFP node can answer questions like:

  • "Which farmers within 3km have tomatoes available right now?"
  • "What's the current wholesale price of potatoes in this region?"
  • "Which stores near me are broadcasting a donation?"

No scraping. No stale listings. Live, structured, geographic data — in a format any system can query.


Current status & what's next (v0.2 targets)

ID Topic
A Ed25519 message signing for trustless cross-node verification
B Supply & Demand Radar — Ask/Donation signals aggregate into cell-level heat maps
C Map route animation from TA cell pairs
D MQTT profile for IoT farm sensors
E USSD/SMS fallback for participants with no smartphone
I Conformance test suite

Read the spec. Build on it. Break it.

Full specification: djowda.com/difp

Download: DIFP-v0.1-Provisional.docx

Contact: sales@djowda.com

License: CC-BY 4.0 — free to implement, fork, extend, and commercialize. Credit required.


The food system doesn't need another closed platform. It needs a shared language.

We just published ours. 🌍

Top comments (0)