
Emem — Earth Memory Protocol
- 48 repo stars
- Updated July 27, 2026
- Vortx-AI/emem
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads.
About
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads. The planet is cut into fixed cells about 9.55 m across, the way a page is cut into words. One measurement at one cell is a **fact**: an elevation, a rainfall total, this year's forest loss, a satellite embedding. Every fact is signed. When an agent asks about a place nobody has measured yet, the responder pulls the value from a real satellite source, signs it, and hands it back in the same respons Exposes 81 MCP tools including io.github.Vortx-AI/emem, EMEM_BIND, EMEM_DATA, EMEM_PUBLIC_URL. Install via Claude Desktop, Cursor, or any MCP-compatible client using the upstream server manifest.
- H 'content-type: application/json' \
- d '{"q":"Bengaluru"}' | jq .cell64
- H 'content-type: application/json' \
- d '{"cell":"defi.zb493.xuqA.zcb5f","bands":["weather.temperature_2m"]}' \
- H 'content-type: application/json' \
Emem — Earth Memory Protocol by the numbers
- Exposes 81 verified tools (MCP introspection)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
claude mcp add --transport http emem https://emem.dev/mcpAdd your badge
Show developers this MCP server is listed on Skillselion. Paste this into your README.
| repo stars | ★ 48 |
|---|---|
| Transport | HTTP |
| Auth | None |
| Tools | 81 |
| Last updated | July 27, 2026 |
| Repository | Vortx-AI/emem ↗ |
How do I connect emem - Earth memory protocol to my MCP client?
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads.
Who is it for?
Teams wiring emem - Earth memory protocol into Claude, Cursor, or custom agents for databases.
Skip if: Skip when you need a non-MCP SDK or hosted API without stdio/SSE transport.
What you get
Working emem - Earth memory protocol MCP server with verified tool registration and client config.
- Agent access to Earth memory reads via MCP tools
- Local persistent emem node with sled cache on EMEM_DATA
- Integratable place identities for downstream app logic
By the numbers
- [object Object]
emem — Earth memory protocol capabilities & compatibility
- Capabilities
- emem earth memory protocol mcp tool registrati · emem earth memory protocol client configuratio · emem earth memory protocol agent workflow inte
- Use cases
- orchestration
- Runs
- Remote server
What emem — Earth memory protocol says it does
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads.
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads.
Tools 81
Public tool metadata - what this server can do for an agent.
emem_locate4 paramsResolves a place mention (free-text name, address, or lat/lng) to the protocol's cell64 identifier, and returns the topic-grouped inventory of bands and algorithms available at that location. When to use: Use whenever the input refers to a real-world location and the next step needs the cell64 identifier or wants to know which bands are available before recalling. The response carries `data_at_this_cell` with three sub-fields: `live_bands_by_topic` (every band recallable here, grouped by topic such as flood_water_event_window, vegetation_condition, built_up_human_geography), `algorithms_for_topic` (composition recipes that fuse those bands into named scores), and `declared_but_no_materializer_at_this_responder` (cube slots reserved without a live connector). For the single-shot path that runs the full chain server-side and returns one packaged answer, use `emem_ask` instead.
latnumberWGS-84 latitude in degrees, paired with `lng`. REQUIRED with `lng` unless `place`/`q` is provided.lngnumberWGS-84 longitude in degrees, paired with `lat`. REQUIRED with `lat` unless `place`/`q` is provided.placestringFree-text place name (e.g. 'Mount Everest', 'Tokyo'). REQUIRED unless `lat`+`lng` is provided. Aliases also accepted: `q`, `query`, `name`.qstringAlias for `place` — accepted because OSM/Mapbox/Google Geocoding all use `q`. Provide either this or `place` (or `lat`+`lng`).
emem_ask8 paramsSingle-shot free-text answer about a real-world location, backed by signed satellite/elevation/water/built-up receipts. Forwards a place mention plus a question; runs the locate → recall → algorithm chain server-side; returns one packaged envelope. When to use: Use when the question concerns a specific real-world place and a packaged, citation-bearing answer is preferable to manual primitive composition. Forward the user's question verbatim as `q` plus the location as `place` (free text), `cell` (cell64), or `lat`+`lng`. The server resolves the location, classifies the question to a topic, recalls every relevant band (auto-materializing Sentinel-2 / Sentinel-1 / Cop-DEM / JRC GSW / Overture / weather on miss), surfaces the algorithm recipes that compose those bands into named scores, and returns a single envelope with `topic_routing`, `facts`, `algorithms_for_question`, an optional Sentinel-2 RGB scene URL, and a `caveats` block (grid resolution, revisit cadence). All facts are signed
cellstringcell64 string (alternative to `place` — use when you have one from a prior emem_locate / emem_recall response). Provide this OR `place` OR `lat`+`lng`.includearrayOpt-in heavy response sections. Default response is slim (~5 KB): answer + algorithm key + fact_cids + caveats. Name specific sections to include them. Ignored when verbose=true (which includes everything).include_imagebooleanBundle a Sentinel-2 RGB scene URL for the resolved cell. Adds ~1-2 s on first call.latnumberWGS-84 latitude (paired with `lng`; alternative to `place` / `cell`).lngnumberWGS-84 longitude (paired with `lat`).placestringFree-text place name (e.g. "Mount Fuji", "Ashok Nagar, Ranchi"). REQUIRED unless `cell` or `lat`+`lng` is provided. Extract the noun phrase from the user's turn; the responder geocodes via OSM Nominatim.qstringrequiredUser's natural-language question about the place (e.g. "is this neighbourhood flood-prone").verbosebooleanWhen true, return the full envelope: per-algorithm formula strings, temporal_recipe blocks, per-fact band_metadata duplicates, and the long _explanation prose. Default (since 2026-05-05) is false so the response fits MCP's 25 KB cap; the signed receipt + fact CIDs + algorithm keys + algorithms_cid are always retained. Pass true to get the full body when debugging.
emem_hunt3 paramsEvent-discovery sweep: pick an event keyword (algal_bloom, deforestation, flood_extent, wildfire, urban_heat_island, methane_plume, landslide, drought, soil_salinity, crop_stress, water_turbidity, oil_slick) plus a region (free-text name or polygon_bbox). The responder geocodes the region, fans out across up to 32 sampled cells, recalls each event's primary scalar input band, and returns the top 8 hotspots ranked by that scalar — each carrying its cell64, lat/lng, the recalled value, a fact_cid for citation, and a scene.png URL. Bypass for free-text input is `emem_ask` (the classifier in /v1/ask routes "find X in Y" questions to the same hunter path). When to use: Call when the user asks an open-world discovery question ("find oil spills in the Persian Gulf", "where is deforestation happening in the Amazon", "show me algal blooms in Lake Erie", "hunt wildfires across California"). Surface 3–8 hotspots with their scene.png as image attachments and quote at least one fact_cid. For `oil_
eventstringrequiredEvent keyword. Maps to one registered detection algorithm: algal_bloom → algal_bloom_chlorophyll_ndci@1, deforestation → deforestation_alert_ndvi_drop@1, flood_extent → flood_extent_sar_threshold@1, wildfire → wildfire_burn_intensity_dnbr_finetune@1, urban_heat_island → urban_heat_island_lst_canopy@1, methane_plume → methane_plume_swir_anomaly@1, landslide → landslide_post_event_sar_dnn@1, drought → spi_meteorological_drought@1, soil_salinity → soil_salinity_index@1, crop_stress → crop_stress_score@1, water_turbidity → water_turbidity_red_band@1. `oil_slick` has no algorithm in the registry yepolygon_bboxobjectExplicit polygon bbox; alternative to `region`. Provide when you already have coordinates from a prior locate / recall_polygon call.regionstringFree-text region (e.g. "Persian Gulf", "Sahel", "Lake Erie", "California"). Resolved through the same geocoder as /v1/locate. REQUIRED unless `polygon_bbox` is provided.
emem_eudr_dds6 paramsProduce a Due Diligence Statement per Regulation (EU) 2023/1115 for one or more plots. Each plot carries operator-supplied geometry (GeoJSON Polygon for >4 ha, Point for ≤4 ha non-cattle per Article 2(28)), country of production (ISO3), Combined Nomenclature code (HS-6+), and quantity in kg. The endpoint applies the regulation's 10 % canopy / 0.5 ha / 5 m height forest definition (Article 2(4)) using the EU Commission's expected JRC GFC2020 V3 baseline plus Hansen GFC v1.12 loss-year confirmation; Sims et al. 2025 driver attribution and RADD SAR fallback layer on when those connectors are wired (Absence today). The response is an Annex II-shaped envelope with per-plot verdict (pass/fail/not_in_scope/indeterminate/below_mmu), failing-cell fraction, and signed fact CIDs for every per-cell verdict — operators quote them in the company's Article 12 record. Article 9(1)(b) legality (land tenure, FPIC, country-of-origin laws) is structurally out of EO scope; the response carries an explicit
cut_off_datestringEUDR cut-off date in ISO 8601. The regulation's value is 2020-12-31; only loss after this date counts as failure.forest_baseline_overridestringOptional baseline override. Default 'jrc_gfc2020_v3' is the EU Commission's expected (non-binding) baseline. Acceptable: 'jrc_gfc2020_v3', 'hansen_only', 'both'.legality_modulestringOperator-chosen legality provider. Default null surfaces the explicit Article 9(1)(b) out-of-EO-scope disclaimer.max_cells_per_plotintegerSample budget per POLYGON plot. Omit to auto-derive from polygon area (~110 cells/ha, clamped to 51,200) so the whole plot is evaluated; EUDR plots are typically large, so do not set a small value unless you have a tight latency budget. POINT plots evaluate at 1 cell.operatorobjectplotsarrayrequiredOne or more plots to evaluate for EUDR compliance.
emem_spi4 paramsCompute the Standardized Precipitation Index (McKee et al. 1993) at a cell: fit a gamma distribution to the same-window precipitation-accumulation history, then standardize the current accumulation to a z-score and map it to a drought class (extreme/severe/moderate drought … normal … wet). Supply `precip_history_mm` + `current_accumulation_mm` directly, or omit them to read the stored `weather.precipitation_mm` trajectory and build the window accumulations server-side. `window_days` selects SPI-1 (30 d), SPI-3 (90 d, default), SPI-12 (360 d), etc. When to use: Call when the user asks 'is this place in drought', 'how dry is it relative to normal', or wants a precipitation-anomaly z-score. The response is honest: when fewer than the WMO-recommended minimum samples exist it returns verdict=`inconclusive` with `spi:null` and a `honest_note` rather than fabricating a z-score from a handful of points. Quote the `spi`, `spi_class`, and `n_samples`. For raw precipitation use `emem_weather`; S
cellstringrequiredcell64 or place name.current_accumulation_mmnumberCurrent-window accumulation (mm); required when precip_history_mm is supplied, else taken as the most-recent window from the stored series.precip_history_mmarrayOptional explicit same-window precipitation accumulations (mm). When omitted the endpoint reads the stored weather.precipitation_mm trajectory.window_daysintegerAccumulation window (SPI-3 = 90 d default; SPI-1 = 30 d; SPI-12 = 360 d).
emem_burn_severity3 paramsCompute the differenced Normalized Burn Ratio (dNBR = NBR_pre − NBR_post; Key & Benson 2006) and map it to the USGS burn-severity classes (unburned / low / moderate-low / moderate-high / high). Supply `nbr_pre` + `nbr_post` (pin the scenes bracketing the fire date) for a correct result, or omit both to use the two most-recent stored `indices.nbr` scenes (older=pre, newer=post) as a coarse estimate. When to use: Call after a wildfire to quantify how badly an area burned, or to triage post-fire severity across a region cell-by-cell. Best practice: explicitly pass `nbr_pre`/`nbr_post` from scenes that bracket the known fire date — the stored-trajectory fallback just takes the two most-recent scenes and may not bracket the fire. Surface `dnbr` and `severity_class`. For active-fire detection use `emem_hunt` with the wildfire event instead.
cellstringrequiredcell64 or place name.nbr_postnumberPost-fire NBR. When both nbr_pre and nbr_post are omitted the endpoint uses the two most-recent stored indices.nbr scenes (older=pre, newer=post).nbr_prenumberPre-fire NBR. Pin the scene just before the fire date for a correct result.
emem_rice_ch47 paramsEstimate seasonal CH4 emissions from rice cultivation per IPCC 2019 Refinement Eq 5.1: integrate the daily emission factor over the cultivation period with water-regime scaling (SFp pre-season, SFo organic amendment) and an optional Yan-2005 Q10 temperature modifier. `cultivation_period_days` and the regional `efc_kg_ch4_ha_day` (Table 5.11) are REQUIRED — the endpoint refuses to guess a global default because the regional EFc drives the magnitude (~30% bias if wrong). An NDWI series (supplied or read from stored `indices.ndwi`) informs the flooding-regime context. When to use: Call for paddy-rice GHG inventory / MRV work where the user needs kg CH4 per hectare for a cultivation season. The caller MUST pick the IPCC region's EFc row (Table 5.11) and the cultivation-period length; pass SFp/SFo when the water regime or organic amendment is known. Surface the seasonal emission, the EFc used, and the scaling factors so the inventory is auditable. For enteric/fertilizer pathways use the de
cellstringrequiredcell64 or place name.cultivation_period_daysnumberrequiredCultivation-period length in days (typically 110–150). REQUIRED — IPCC Eq 5.1 integrates the daily EF over this period; no defensible global default.efc_kg_ch4_ha_daynumberrequiredRegional baseline EFc (kg CH4/ha/day) from IPCC 2019 Table 5.11. REQUIRED — pick the row for the cell's IPCC region (Asia.S 0.85, Asia.SE 1.22, Europe 1.56, …); the global 1.19 default would bias inventories ~30%.ndwi_seriesarrayOptional explicit NDWI series across the cultivation period. When omitted the endpoint reads the stored indices.ndwi trajectory.sfonumberOrganic-amendment scaling factor SFo (Table 5.14); default 1.00 (no amendment).sfpnumberPre-season water-regime scaling factor SFp (Table 5.13); default 0.68 (non-flooded pre-season > 180 d).t_paddy_cnumberMean paddy-water temperature (°C) for the Yan-2005 Q10 modifier; omit to disable the temperature correction (T_mod = 1).
emem_deforestation_alert1 paramComposite deforestation-alert score: `alert_score = 0.5·clamp01(ndvi_drop/0.30) + 0.5·clamp01(embedding_change/0.20)`, where `ndvi_drop = max(0, ndvi_modis_baseline − ndvi_now)` and `embedding_change = 1 − cos(tessera_latest, tessera_prev)`. Each half degrades INDEPENDENTLY and honestly: if a band is missing, that half is dropped AND the output is renamed so a half-score can never be mistaken for the full composite. If NEITHER half is computable the response is a signed `inconclusive` carrying no number. Every response also carries a machine-readable `degraded` boolean plus `degraded_reason` (closed set: `embedding_half_unavailable`, `ndvi_half_unavailable`, `no_inputs`) and `degraded_message`, so a caller gates on the flag instead of parsing prose. When to use: Call to flag recent forest-loss-like change at a known cell when you want a single 0..1 alert score rather than a full ensemble. Gate on `degraded`/`degraded_reason`: a half-score (`degraded:true`) must NOT be thresholded agai
cellstringrequiredcell64 or place name.
emem_sar_forest_disturbance2 paramsCloud- and night-independent Sentinel-1 C-band confirmation of forest disturbance. Intact forest scatters VV strongly + stably (canopy volume scattering); clearing collapses that term so VV backscatter DROPS ~3-5 dB. Samples VV at a baseline-year July-1 anchor and the latest scene, reports `vv_drop_db = baseline − recent` and a `disturbed` flag when the drop ≥ 3 dB (Reiche et al. 2018, RSE 204:147). Both VV reads are signed Primary facts; the response cites both fact_cids. Honest `inconclusive` when either S1 vintage is unavailable. Source: Microsoft Planetary Computer sentinel-1-rtc (anonymous SAS — no requester-pays, no API key). When to use: Call to corroborate or scout forest clearing where cloud blocks the optical products — radar sees through cloud and at night, catching wet-season clearing the annual Hansen/JRC-TMF layers and a single cloudy Sentinel-2 pass miss (the gap RADD was meant to fill). This is an ADDITIVE scout signal, NOT a standalone legal verdict: a VV drop can als
baseline_yearintegerBaseline calendar year the VV drop is measured against (default 2020, the EUDR cut-off year). Baseline VV is sampled at a July-1 anchor of this year; the recent VV is the latest scene.cellstringrequiredcell64 or place name.
emem_triple_consensus2 paramsThree-encoder change ensemble: compute the cosine change between the two most-recent DISTINCT vintages for each of the Clay, Prithvi, and Tessera embeddings at the cell, then vote each encoder's change against `consensus_threshold` (registry default 0.15). Returns each encoder's change magnitude, its vote, and the consensus verdict (how many of the three agree change happened). Degrades to a signed `inconclusive` when the GPU sidecar is unreachable or a cell lacks two distinct vintages for the encoders. The response carries a machine-readable `degraded` boolean, a `degraded_reason` (closed set: `gpu_sidecar_unavailable`, `single_vintage`, `outside_coverage`, `no_finite_overlap`, `recall_failed`, `partial_consensus_N_of_3`, `insufficient_encoders`), and `degraded_message`; each `encoders_absent[]` entry also carries its own `reason_code`. A 2-of-3 result reports `degraded:true` even though it still carries a real ensemble number. When to use: Call when the user wants a robust, model-ag
cellstringrequiredcell64 or place name.consensus_thresholdnumberOverride the registry consensus gate (default 0.15); clamped to (0,1).
emem_terrain2 paramsCompute three standard DEM terrain indices from one 3×3 Copernicus-DEM (copdem30m.elevation_mean) neighbourhood at a cell: Horn (1981) slope in degrees, Riley (1999) Terrain Ruggedness Index (TRI = sqrt(Σ(Z_centre−Z_i)²)), and Weiss (2001) Topographic Position Index (TPI = Z_centre − mean(neighbours); positive = ridge, negative = valley). The 8 neighbour cell64s are derived by perturbing the cell's lat/lng one cell pitch per axis; the east-west ground spacing is cos(lat)-corrected. When to use: Call when the user asks how steep / how rugged / ridge-or-valley a place is, for siting (solar, construction, agriculture), erosion/landslide screening, or habitat-heterogeneity inputs. Slope and TRI need the full 8-neighbour ring; TPI degrades to ≥1 neighbour. Copernicus DEM is bathymetry-free, so ocean cells return a signed `inconclusive` rather than a fabricated slope — read each index's own `verdict`. For raw elevation use `emem_elevation`.
cellstringrequiredcell64 or place name. The 8 neighbour cell64s are derived by perturbing the decoded lat/lng step_cells pitches per axis.step_cellsintegerStencil step in cell64 pitches (default 3 ≈ 28.7 m, matching the ~30 m Copernicus DEM native resolution). step_cells=1 samples below the DEM resolution and reads flat inside one source pixel; raise it to measure slope at a coarser scale.
emem_region_similarity3 paramsAnswer 'how alike are these two places?' Mean-pool the 128-D GeoTessera embedding across each region's cells to get a centroid, then return the cosine similarity in [-1,1] (+1 = identical landscape, 0 = unrelated). Each region is {place} | {polygon_bbox} | {cells}. CPU-fetched embeddings — no GPU sidecar needed. Surfaces how many cells in each region actually carried a vector (coverage). When to use: Call to compare two areas at the level of overall land character (e.g. 'is this valley like that one?', 'find me somewhere that looks like X'). Degrades to a signed `inconclusive` (no number) when a region has no embedding-covered cells. For a single cell-to-cell vector cosine use `emem_compare`; for k-NN retrieval use `emem_find_similar`.
max_cellsintegerPer-region cell cap.region_aobjectrequiredFirst region: {place} | {polygon_bbox:{min_lat,max_lat,min_lng,max_lng}} | {cells:[cell64,...]}.region_bobjectrequiredSecond region, same shape as region_a.
emem_embedding_centroid4 paramsMean-pool the 128-D GeoTessera embedding over a region's cells: centroid = (1/N) Σ v_i, plus the L2-normalised centroid and a content-addressed centroid_cid. The building block region_similarity composes. Region is {place} | {polygon_bbox} | {cells}. NaN dims are averaged over their finite contributors. CPU-only. When to use: Call when you need one representative embedding vector for an area — to feed similarity search, clustering, or a linear probe over places rather than single cells. Returns a stable centroid_cid for citation. Signed `inconclusive` when no cell in the region carried a vector.
cellsarrayExplicit cell64 list (taken verbatim, capped by max_cells). Alternative to place/polygon_bbox.max_cellsintegerCap on cells sampled from the region; surfaced as coverage_capped.placestringFree-text place name; resolved through the layered geocoder to a polygon bbox, then sampled. One of place/polygon_bbox/cells required.polygon_bboxobjectExplicit bbox; sampled on a grid. Alternative to place/cells.
emem_embedding_diversity4 paramsQuantify how varied a region's landscape is: diversity = (1/(N(N-1))) Σ_{i<j} (1 − cosine(v_i, v_j)), the mean pairwise cosine distance over the region's GeoTessera embeddings. 0 = perfectly uniform; higher = more heterogeneous land cover (a determinantal-point-process / k-medoid diversity). Region is {place} | {polygon_bbox} | {cells}. CPU-only. When to use: Call for habitat-heterogeneity / biodiversity-proxy inputs, or to tell a monoculture from a mosaic landscape, or to rank regions by how mixed they are. Needs ≥2 embedding-covered cells, else a signed `inconclusive`. Pair with `emem_terrain` ruggedness for a fuller heterogeneity picture.
cellsarrayExplicit cell64 list (taken verbatim, capped by max_cells). Alternative to place/polygon_bbox.max_cellsintegerCap on cells sampled from the region; surfaced as coverage_capped.placestringFree-text place name; resolved through the layered geocoder to a polygon bbox, then sampled. One of place/polygon_bbox/cells required.polygon_bboxobjectExplicit bbox; sampled on a grid. Alternative to place/cells.
emem_neighborhood_consistency1 paramScore how much a cell looks like its surroundings: consistency = (1/8) Σ cosine(centre, neighbour_i) over the 8 immediate cell64 neighbours, plus outlier_score = 1 − consistency. High consistency = the cell blends in (Tobler's First Law); high outlier_score = it stands out — an edge, a fresh clearing, a built patch in farmland. CPU-only GeoTessera embeddings. When to use: Call to flag a cell that is anomalous versus its local neighbourhood (change/edge detection, QA of a homogeneous expectation, scouting for the odd-one-out). Signed `inconclusive` when neither the centre nor any neighbour carried an embedding. For year-over-year change at one cell use `emem_state_diff` or `emem_triple_consensus`.
cellstringrequiredTarget cell64 or place name. Scored against its 8 immediate cell64 neighbours.
emem_state9 paramsGet one dense numeric fingerprint that summarises everything known about a place — ready to feed into similarity search, a classifier, or clustering. Two views: `encoder` returns a single AI-model embedding (128-D Tessera, 1024-D Clay, 1024-D Prithvi); `cube` returns the full 1792-D vector concatenated across every band, with a per-band coverage manifest. When to use: Call this when the user wants a machine-usable summary of a place rather than individual band readings — e.g. 'give me a feature vector for this location', 'how do I represent this place for ML', or before running similarity / linear-probe / clustering downstream. Also use it to get one rebindable handle (`memory_token` / `state_cid`) that cites the whole place. Default `view=encoder` is the cheap single-recall path; pass `view=cube` for the full attested view (its `coverage[]` lets you tell signed-zero from not-yet-materialised). Then hand the vector to `emem_find_similar` (k-NN), `emem_compare` (two-place cosine), or `
as_of_signed_atstringBi-temporal transaction-time bound (RFC 3339).as_of_tslotintegerBi-temporal valid-time bound — forwarded to the underlying recall. Lets `/v1/state` answer `what did this place look like as of date X` for both encoder and cube views.cellstringrequiredcell64 OR free-text place name.encoderstringFor `view=encoder`: which vector band to read. Defaults to `geotessera`.familiesarray`view=cube` only. Limit the cube to a subset of band families (e.g. ["foundation","vegetation"]). Slots from other families report `status:"filtered_out"`.include_reservedboolean`view=cube` only. Include declared-but-inert placeholder slots (`_reserved_128`, `reserved`) in the coverage manifest. Default false.materializeboolean`view=cube` only. Opt in to FULL auto-materialisation. Default false. The cube view auto-warms geotessera on a cold cell regardless of this flag, so view=cube is never less informative than view=encoder.tslotintegerOptional tslot bucket; omit for natural per-band vintages.viewstringDefault `encoder` (single-band native vector). Pass `cube` for the full 1792-D voxel with coverage manifest, full-fidelity extras, and a humanised `scalars` map.
emem_state_multi5 paramsGet the place's fingerprint from several AI models at once (`geotessera`, `clay_v1`, `prithvi_eo2`, `galileo`) in one call, returned as a per-model map. Each model is tried independently; any that can't produce a vector here show up under `missing` with a reason instead of failing the whole request. When to use: Call this when the user wants a second (or third) opinion on what a place looks like — 'do the different models agree this is forest / urban / water?', 'which model has the freshest read here?', or when you want all the embeddings concatenated for a stronger downstream classifier. Use the single-model `emem_state` instead when one embedding is enough. Pass `encoders: [...]` to narrow the set.
as_of_signed_atstringBi-temporal transaction-time bound (RFC 3339).as_of_tslotintegerBi-temporal valid-time bound — forwarded to every per-encoder recall.cellstringrequiredencodersarrayOptional explicit list; defaults to all wired foundation encoders (`geotessera`, `clay_v1`, `prithvi_eo2`, `galileo`).tslotinteger
emem_state_diff4 paramsVector delta between the same cell at two tslots: returns the per-element residual, its L2 norm (scalar change-magnitude), the cosine between the two source vectors (orientation drift), and both source fact CIDs so the agent can quote both attestations as evidence. When to use: Call when the user asks 'how much did X change between A and B' for a foundation embedding at one place. Pass `tslot_a` and `tslot_b` (must differ); default `encoder=geotessera`. For per-band scalar change (NDVI delta, elevation delta) use `emem_diff` instead.
cellstringrequiredencoderstringDefault `geotessera`.tslot_aintegerrequiredFirst tslot.tslot_bintegerrequiredSecond tslot; must differ from `tslot_a`.
emem_memory_token2 paramsCompose a `memt:<cell64>:<fact_cid>` (or `memt:<cell64>:<state_cid>`) citation handle. Validates both components are non-empty and do not contain the outer separator `:`. When to use: Call when the agent wants a single rebindable string to cite a place + attested fact across messages, threads, or tools. The token is the recommended way for agents to pass earth-memory citations to other agents without re-fetching. Pair with `emem_verify_receipt` on the receiving end to verify the signed payload.
cellstringrequiredcell64 — neither component may contain `:`.fact_cidstringrequired26-char base32-nopad-lowercase content-id of the fact.
emem_memory_token_resolve1 paramParse a `memt:<cell64>:<fact_cid>` citation handle and return the signed fact body the cid binds. Saves the agent from string-splitting the token and chaining `GET /v1/facts/<cid>` manually. When to use: Call when an agent receives a memory_token from another agent (or out of a previous turn) and wants the underlying signed bytes. The response carries the parsed cell + fact_cid, the full fact body, and the stable `fact_url` an agent can hand to any other peer. 404 with a typed code if the responder doesn't hold the cid; try /v1/fetch with the cid then, or paste the token at a mirror.
tokenstringrequiredA `memt:<cell64>:<fact_cid>` citation handle to dereference.
emem_memory_bundle2 paramsCompose N (cell, band, tslot?) triples into ONE signed envelope. Each triple runs through the standard auto-materialize recall path; the resulting fact_cids are bundled into a content-addressed envelope and the responder signs over the full receipt. The composed `bundle_token` is `memb:<bundle_cid>` — a single rebindable string that cites the whole set. When to use: Call when the agent wants to cite multiple (place, band, vintage) facts as one handle. The bundle stays verifiable offline via /v1/verify_receipt (the receipt covers all cited fact_cids and cells). Use this instead of N separate `emem_memory_token` composers when the citation is conceptually one thing (e.g. "the EUDR-relevant baseline for these 8 plots at 2020-12-31").
purposestringOptional human-readable purpose string. Included in the bundle_cid preimage so the same triples + different purposes produce distinct CIDs.triplesarrayrequiredOne or more (cell, band, tslot?) triples to bundle. Each entry is recalled through the standard auto-materialize path; the bundle envelope cites every resulting fact_cid.
emem_memory_bundle_resolve1 paramParse a `memb:<bundle_cid>` token and return the signed bundle envelope: every citation (cell, band, resolved_tslot, fact_cid, memory_token), the receipt, the responder pubkey, and the deduped flat cells[] / fact_cids[] arrays. Returns 404 with a typed code when the responder does not hold the bundle. When to use: Call when an agent receives a `memb:` token from another agent (or earlier turn) and wants the underlying signed citation set. The response is byte-identical to what `emem_memory_bundle` returned at the original responder.
tokenstringrequiredA `memb:<bundle_cid>` rebindable handle to dereference.
memory_view4 paramsRead the contents of a memory file at `/memories/<path>` or list a directory when the path ends with `/`. Optional `view_range: [start, end]` slices a 1-indexed inclusive line range out of the file. Mirrors the `view` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the model running with `betas: ['context-management-2025-06-27']` issues a `view` against its memory directory. Use `/memories/` (trailing slash) to enumerate files; `/memories/notes.md` to read one. Returns a 404 with typed code on missing path.
kindstringOptional kind filter when listing a directory. Restricts entries to one memory type (episodic|semantic|procedural|resource).pathstringrequired`/memories/<file>` for a file, or `/memories/<subdir>/` for a directory listing. Must stay under `/memories/`.vault_capabilitystringOptional Vault capability: an ed25519 signature (base32-nopad-lc) over blake3("emem.vault_open|"+path+"|"+nonce_bytes), verifiable under the responder pubkey that sealed the entry. When the path is a Vault entry and this verifies, memory_view returns decrypted plaintext; otherwise it returns ciphertext-only. Ignored for non-vault paths.view_rangearrayOptional [start_line, end_line] inclusive, 1-indexed. Lets the agent read part of a long file.
memory_create4 paramsWrite a memory file at `/memories/<path>` with the supplied `file_text`. Overwrites if the file exists. Persists to sled, content-addresses the bytes (`file_cid`), and signs the write so the operation carries a verifiable receipt. Mirrors the `create` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the LLM issues a `create` against its memory directory (initial scratchpad write, refresh of a notes file, etc.). The response carries the new `file_cid` and a signed receipt the agent can quote in audits.
attesterobjectOptional ed25519 caller binding. Required for writes under `/memories/by_attester/<pubkey8>/...`. Shape: {pubkey_b32, sig_b32} where sig signs blake3("emem.memory_write|create|path|body_hash").file_textstringrequiredFull file contents.kindstringOptional memory typing tag. Default `resource`. `episodic` = observation; `semantic` = learned fact; `procedural` = playbook; `resource` = generic scratchpad; `vault` = AEAD-sealed secret (stored encrypted; memory_view returns ciphertext-only unless a valid ed25519 capability over blake3("emem.vault_open|"+path+"|"+nonce) is supplied; never indexed by memory_search).pathstringrequired`/memories/<file>` path. Overwrites if the file exists. Must stay under `/memories/`.
memory_str_replace5 paramsReplace `old_str` with `new_str` in the named memory file. Fails (no partial write) when `old_str` is absent or matches more than once. Writes a new content-addressed `file_cid` and signs the receipt. Mirrors the `str_replace` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the LLM issues a `str_replace` against its memory file — typical for small targeted edits. The strict single-match contract is the contract Claude expects: an LLM that sees a single-match diff knows the change applied where it intended.
attesterobjectOptional ed25519 caller binding. See memory_create for the preimage shape (verb=str_replace).kindstringOptional memory typing override. If omitted the existing kind is preserved.new_strstringrequiredReplacement substring.old_strstringrequiredExact substring to replace. The whole call fails (no partial write) when the old_str is absent or appears more than once.pathstringrequired`/memories/<file>` path the replacement targets.
memory_insert5 paramsInsert `new_str` after the given 1-indexed line in the named memory file. `insert_line: 0` inserts at the top. Writes a new `file_cid` and signs the receipt. Mirrors the `insert` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the LLM wants to append a new line to a memory file without rewriting it. For top-of-file inserts, pass `insert_line: 0`; for end-of-file, pass the current line count (the responder rejects out-of-range with a typed error).
attesterobjectOptional ed25519 caller binding. See memory_create for the preimage shape (verb=insert).insert_lineintegerrequired1-indexed line number AFTER which to insert. 0 inserts at the top of the file.kindstringOptional memory typing override. If omitted the existing kind is preserved.new_strstringrequiredText to insert. A trailing newline is preserved if present; one is added otherwise.pathstringrequired`/memories/<file>` path the insertion targets.
memory_delete2 paramsDelete a memory file at `/memories/<path>`. When the path ends with `/`, every file beneath the directory is removed. Updates the path index but leaves prior content-addressed blobs in place (the audit history is append-only). Mirrors the `delete` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the LLM issues a `delete` against a memory file or subdirectory it no longer needs. Existing receipts citing the old file_cid stay verifiable — the blob is content-addressed, only the path → file_cid index forgets.
attesterobjectOptional ed25519 caller binding. Required for `/memories/by_attester/<pubkey8>/...`. Body is empty for delete; sig signs blake3("emem.memory_write|delete|path|body_hash") where body_hash = blake3("").pathstringrequired`/memories/<file>` or `/memories/<subdir>/` to delete. Directories drop every file beneath them.
memory_rename3 paramsMove (rename) a memory file from `old_path` to `new_path`. Both paths must stay under `/memories/`; `new_path` must not already exist. The file_cid is preserved (no re-sign) so the prior receipt still binds the bytes. Mirrors the `rename` verb in Anthropic's context-management-2025-06-27 memory tool spec. When to use: Call when the LLM wants to rename or move a memory file. Failure modes: source missing, destination already exists, path escapes `/memories/`.
attesterobjectOptional ed25519 caller binding (verb=rename). Required when either path is under `/memories/by_attester/<pubkey8>/...`.new_pathstringrequiredDestination `/memories/<file>` path. Fails when the destination exists.old_pathstringrequiredExisting `/memories/<file>` path.
memory_list_by_kind3 paramsList memory files by their typed `kind` (episodic | semantic | procedural | resource). Optional path prefix narrows the scan; results are sorted by signed_at descending. The kind taxonomy follows the CoALA / LangMem / MIRIX agent-memory ontology: `episodic` = observations of events, `semantic` = durable learned facts, `procedural` = playbooks, `resource` = generic durable scratchpad (default for back-compat). When to use: Call when an agent wants only one slice of its memory (e.g. surface every semantic fact it has learned about a topic) without scanning the full directory tree. Pair with memory_view for read-back of a specific entry.
kindstringrequiredMemory type to enumerate.limitintegerMaximum entries to return (default 256, cap 2048). Results are sorted signed_at desc.prefixstringOptional path prefix filter, e.g. `/memories/by_attester/abcd1234/`.
emem_memory_search5 paramsSemantic search over /memories/* file contents using BGE-base-en-v1.5 (768-D, L2-normalised) backed by a Lance partition (`memory_text_index_d768.lance`). Matches paraphrases — "rainfall in March" finds "precipitation observed in spring" without an exact substring match. Returns ranked hits with similarity in [0,1], 200-char snippets around the best-matching chunk, and the signing receipt's path / file_cid / signed_at / attester_pubkey_b32 fields. Filters: `kind`, `path_prefix`, `attester_pubkey_b32`. Falls back to a brute-force scan (slower but correct) when the index is empty or `EMEM_DISABLE_LANCE=1` is set; the `via` field of the response reports which path was taken. When to use: Call instead of paging through `memory_view` whenever the agent knows roughly what it wants (a topic, a name, a paraphrase) but not the exact file path. Pair with `memory_view` for the full body once you've narrowed down the candidate — `emem_memory_search` returns a 200-char snippet, not the whole file.
attester_pubkey_b32stringOptional filter: only files attested by this signer (base32-nopad-lowercase pubkey).kintegerNumber of hits to return.kindstringOptional filter: only files whose typing taxonomy entry matches (defaults to `resource` until Agent W's typing lands).path_prefixstringOptional filter: only files whose path starts with this prefix (e.g. `/memories/journal/`).qstringrequiredFree-text query. Semantic — matches paraphrases not just substrings.
emem_corpus_state_statsSigned snapshot of corpus liveness: distinct_cells, distinct_bands, facts_scanned, top per-band counts, manifest CIDs. Same payload that backs /v1/stream's corpus.state tick (signed). Use this for a one-shot poll instead of holding an SSE connection. When to use: Call when an agent needs a single liveness reading to surface in a dashboard, attach to a report, or decide whether to refresh local caches. Includes ed25519 signature over a deterministic preimage so the snapshot is verifiable. For a continuous feed, GET /v1/stream over Server-Sent Events instead.
emem_benchmarkHand-verified evaluation items for grading an agent against the responder. Returns {items[], grader_url}. Submit answers (cell64 or fact_cid per item) to POST /v1/benchmark/grade for per-item scores. Items today: elevation recall, NDVI, find_similar neighbours. When to use: Call once at agent-onboarding time (or in CI) to fetch the canonical task list, then have the agent answer each item using its normal tool routing, and POST the answers map to /v1/benchmark/grade for a deterministic score. Lets an operator regression-check that an agent build still hits ground truth.
emem_recall8 paramsRecall facts about a cell — auto-materializes on miss for any band with a registered materializer. When to use: Call after `emem_locate` (or with a known cell64). Returns every Primary fact stored at that (cell, band, tslot). IMPORTANT: if the cell has no fact yet for a requested band AND that band has `has_materializer=true` (per `emem_coverage_matrix` / `emem_materializers`), the responder fetches the upstream value, signs it under its identity, persists it, and returns it in the same response (~180 ms first call, ~10 ms cached thereafter). So for any wired band you can recall ANY cell on Earth without seeding — just pass `bands: [<band>]`. The response carries `materialize_notes` listing what was just fetched. Empty result with no notes means the band has no materializer at this responder.
as_of_signed_atstringBi-temporal transaction-time bound. RFC 3339 string. Returns only facts whose `signed_at` ≤ as_of_signed_at — answers `what did emem KNOW as of system-date Y`. Malformed strings are rejected with code:`invalid_signed_at_format`.as_of_tslotintegerBi-temporal valid-time bound. Returns the latest fact per (cell,band) whose tslot ≤ as_of_tslot — answers `what did this place look like AS OF date X`. Conflicts with an explicit `tslot` when as_of_tslot < tslot (rejected with code:`invalid_temporal_bound`).bandstringoptional single band key — convenience alias for bands:[band]. Use when you want exactly one band (e.g. 'geotessera.2020', 'modis.ndvi_mean') and would otherwise have to wrap it in an array. Both `band` and `bands` are accepted; if both are given they are merged.bandsarrayoptional band keys to filter, e.g. ['indices.ndvi','geotessera']cellstringrequiredcell64 string, e.g. 'damO.zb000.xUti.zde78'includearrayOpt-in response expansion. include:['freshness'] attaches an advisory per-fact freshness block: a Q(Δt) staleness score from the band's physics decay kernel (the same one /v1/temporal_route ranks bands with), so an agent learns how stale each reading is in the call that returns it. Advisory only; it does NOT enter the receipt. include:['edges'] attaches each fact's typed temporal edges and threads their CIDs into the receipt. Absent leaves the response byte-identical to the pre-v0.0.9 recall.scopeobjectOptional multi-tenant scope {user_id, agent_id, run_id, org_id}. When at least one field is set, the recall is FILTERED to facts written under the same four-tuple (a recall scoped to {user_id:'u1'} sees only u1's facts, never another tenant's and never globally-written facts) AND the signed receipt binds the scope. Omit (or send {}) for the global, pre-v0.0.8 recall.tslotintegeroptional time slot (band-tempo-relative integer offset from emem epoch)
emem_recall_polygon8 paramsRecall facts across every cell inside a place's polygon (single signed envelope). Closes the place-name-drift gap for wide features (parks, lakes, regions). When to use: Call when the user names a wide feature (national park, river basin, country, large urban area) where one cell is too small. Pass `place` and the geocoder will fan out across the polygon — or pass `polygon_bbox` directly if you have coordinates. Returns `merged_facts`, `by_cell`, and a `polygon_bbox.source` indicator (`nominatim_boundingbox` = real polygon, `centre_cell_bbox` = fallback to one cell because the geocoder had no polygon). For *farm* queries the OSM polygon is the whole estate envelope; pass `include: ["ftw_fields"]` to additionally attach per-field agricultural-boundary polygons from Fields of The World (CC-BY-4.0) — or call the dedicated `emem_field_boundaries` for the pure-fetch shape.
as_of_signed_atstringBi-temporal transaction-time bound (RFC 3339).as_of_tslotintegerBi-temporal valid-time bound — forwarded to every per-cell recall in the fan-out.bandsarrayBands to recall at each fan-out cell.includearrayOptional supplements attached to the response. `ftw_fields` adds per-field agricultural-boundary polygons from Fields of The World (https://fieldsofthe.world, CC-BY-4.0) for the resolved polygon bbox — useful for farm queries where the OSM polygon is the estate envelope but the user wants the actual fields inside. Adds ~150-500 ms on first call per region (cached thereafter).max_cellsintegerCap on cells sampled from the polygon.placestringFree-text place name; resolved through the layered geocoder. REQUIRED unless `polygon_bbox` is provided.polygon_bboxobjectExplicit polygon bbox; alternative to `place` when caller already has coordinates. REQUIRED unless `place` is provided.tslotinteger
emem_field_boundaries3 paramsPer-field agricultural-boundary polygons from the Fields of The World global product (~3.17B fields, 241 countries, 10 m resolution, CC-BY-4.0). Returns a GeoJSON FeatureCollection with the polygon geometries, FIBOA-compatible properties, and a planar `area_m2` per field — plus provenance (source CID, provider URL, license, attribution). When to use: Call when the user asks about farms, fields, parcels, croplands, plots, or agricultural boundaries inside a region — anywhere the OSM/Nominatim boundary alone is too coarse (the OSM polygon for a farm is its estate envelope; this returns the individual field polygons inside). Pass `place` (free-text) or `polygon_bbox`. For farms wider than ~10 km², split the bbox: the fetcher caps each call at 16 covering tiles. The receipt quotes `license: CC-BY-4.0` and `attribution: Fields of The World / Taylor Geospatial Institute` — surface both with any rendered map. For a one-shot "facts at every cell inside the farm PLUS the field polygons", call
placestringFree-text place/farm/region name; resolved through the same layered geocoder as /v1/recall_polygon. REQUIRED unless `polygon_bbox` is provided.polygon_bboxobjectExplicit bbox; alternative to `place`.zoomintegerWeb-Mercator zoom level for the FTW PMTiles read. Default = library-picked min(14, archive.max_zoom). Higher zoom = sharper boundaries but more tiles per query (capped internally at 16 — split very wide farms).
emem_query_region5 paramsQuery facts over a region (single cell or list of cells), optionally aggregated per band. When to use: Call when the user asks 'how does region X look', 'what's the average NDVI here', or wants a region-level summary. Use `agg=mean|median|p90|vector_centroid` to fold per-band values.
aggstringoptional per-band aggregationas_of_signed_atstringBi-temporal transaction-time bound (RFC 3339).as_of_tslotintegerBi-temporal valid-time bound — applied per cell across the region. See emem_recall for semantics.bandsarraygeometrystringrequiredcell64 string, or 'cells:c1,c2,c3'
emem_compare3 paramsCompare two cells: cosine similarity over shared vector bands + per-band scalar deltas. When to use: Call when the user asks 'how similar is X to Y', 'compare these two places', or wants a difference vector. Returns a single cosine score and per-band deltas.
astringrequiredcell64 of cell Abstringrequiredcell64 of cell Bfamilystringoptional band-key prefix (e.g. 'indices.')
emem_compare_bands6 paramsCompare two bands at the same cell. Scalar pair → metric=delta, value=b-a. Vector pair (equal dim) → metric=cosine + per-dim delta. Returns a signed receipt naming both source fact CIDs. When to use: Call when the user wants cross-source consistency at one place ('does Cop-DEM agree with GMRT here?'), cross-vintage drift ('how did the embedding change between 2017 and 2024 at this cell?'), or any band-vs-band comparison within a single cell. `cell` + `a` + `b` are required. `tslot_a`/`tslot_b` are OPTIONAL: omit them to let the responder auto-pick each band's latest attested tslot — required for medium/fast-tempo bands (NDVI 30-day, MODIS 8-day, weather, CAMS) where there is no fact at tslot=0. The response carries `tslot_resolution` (echoes what was chosen and why) and `bands_with_no_history` (lists any band the cell has no attested fact for).
astringrequiredband A key (e.g. 'copdem30m.elevation_mean')bstringrequiredband B key (e.g. 'gmrt.topobathy_mean')cellstringrequiredcell64 (`cell64` accepted as alias)predicateobjectOptional consistency predicate. When set, the response carries a signed `verdict` (true|false|incomparable) over the comparison.tslot_aintegertslot for band A. Omit to auto-pick the latest attested tslot for this band at this cell — required for medium/fast-tempo bands (NDVI 30-day, MODIS 8-day, weather, CAMS) which have NO fact at tslot=0. The response carries `tslot_resolution.per_band.tslot_used_a` so you see which slot was chosen.tslot_bintegertslot for band B. Same auto-pick semantics as `tslot_a` when omitted.
emem_find_similar6 paramsk-NN over the corpus by cell embedding or inline vector. When to use: Call when the user asks 'find places like X', 'where else looks like this', or hands an embedding to find neighbours. `key` is either a cell64 or `inline:[x,y,...]`. Default band is `geotessera` (128-D Tessera foundation embedding); pass `band: "geotessera.multi_year"` for the 1152-D 9-vintage (2017–2025) fusion.
as_of_signed_atstringBi-temporal transaction-time bound (RFC 3339). Also applied to candidates BEFORE cosine. Same Lance-bypass note as as_of_tslot.as_of_tslotintegerBi-temporal valid-time bound. Applied to candidate cells BEFORE cosine scoring — a cell with no fact whose tslot ≤ as_of_tslot under the scoring band is dropped from the candidate pool (undecidable→drop). When set, the Lance ANN fast-path is bypassed (the index has no signed_at column); brute-force k-NN runs instead so as_of is honoured truthfully.bandstringvector band to scan (default: 128-D Tessera foundation embedding). For mode=hamming/hamming_then_rerank you can pass either the cosine band (e.g. 'geotessera') or its binary sibling ('geotessera.bin128') — the responder picks the right one.kintegerkeystringrequiredcell64 (look up that cell's vector) or 'inline:[x,y,...]' literal vectormodestringScoring mode. cosine = fp32 over full vector (precise, ~256 B/cell scan). hamming = sign-bit popcount over the binary sibling band (~16 B/cell, ~1000× faster, ~65% recall@10). hamming_then_rerank = triage with Hamming on 4·k candidates then re-rank by cosine — matches cosine precision at ~16× less work.
emem_trajectory5 paramsTime series for one (cell, band) over an inclusive [start, end] tslot window. Returns only what's already attested — does NOT trigger materialization. For historical backfill use `emem_backfill`. When to use: Call when the user asks 'how did X change over time' for a band that already has multiple historical tslots seeded. IMPORTANT differences from `emem_recall`: (1) trajectory does NOT auto-materialize past tslots — it returns only facts that have already been attested at this responder, so for fast-tempo bands like `indices.ndwi` you'll typically see ONE point at the latest tslot until an attester seeds history. (2) tslots are non-negative `u64`; there's no negative-offset 'last 2 years' shorthand. For LONG-TERM history questions ('flooded in last 2 years', 'forest loss since 2020') prefer either (a) a static-tempo summary band that one fact answers — `surface_water.recurrence` covers 1984-2021 in a single signed value, no trajectory needed — or (b) `emem_backfill` to materialize a
as_of_signed_atstringBi-temporal transaction-time bound (RFC 3339). Restricts the series to facts signed at or before this instant.as_of_tslotintegerBi-temporal valid-time bound. Skips points with tslot > as_of_tslot — effectively clips the window's upper edge.bandstringrequiredcellstringrequiredwindowarrayrequired[start_tslot, end_tslot] inclusive
emem_diff4 paramsCompute a DerivativeFact (delta) between a band's values at two tslots. When to use: Call when the user asks 'what changed between t1 and t2', 'give me the delta'. Returns a signed DerivativeFact + receipt — the delta itself is content-addressed and citable.
bandstringrequiredcellstringrequiredtslot_aintegerrequiredtslot_bintegerrequired
emem_memory_contradictions5 paramsSurface where the corpus DISAGREES with itself. When two or more independent sources signed different values for the same place + band + time, this returns that disagreement with a 0–1 severity score and citations to every disputed fact — instead of silently picking one value and hiding the conflict. The opposite of a confident single answer: it tells you when not to trust one. When to use: Call this when trust matters before you rely on a number — 'is there disagreement about X', 'do the sources corroborate this', 'audit this claim', or 'find contradictory observations in region Y'. Use it to decide whether a fact is well-corroborated or contested. Narrow with `cell_prefix` (e.g. "defi.zb5") for a region and `band` for one family; `min_severity` filters out trivial differences. Severity is per band kind: scalar = spread over the band's range, vector = 1 − mean cosine, categorical = 1 − mode share. The receipt cites every disputed CID — follow up with `emem_diff` to quantify a pair, o
bandstringBand key filter (e.g. `indices.ndvi`). Omit to include all bands.cell_prefixstringBytewise prefix on cell64 (e.g. `defi.zb5f9`). Omit to scan the whole corpus up to the scan cap.limitintegerMax contradictions to return.min_severitynumberSeverity floor in [0, 1]. 0 = report every disagreement, 1 = only flagrant. Severity scoring is per band kind: scalar (max-min over band range), vector (1 - mean cosine), categorical (1 - mode share).window_unix_sarray[lo, hi] inclusive Unix-seconds filter on attestations' signed_at — all disagreeing attestations must fall in the window.
emem_edges_recall6 paramsRead temporal knowledge-graph edges (subj --pred--> obj, valid over [valid_from, valid_to)), bi-temporally filtered, in EITHER direction. Forward (`subj`, direction="out", the default): edges originating at a subject fact. Reverse (`obj`, direction="in"): edges pointing AT a fact — what disagrees-with / supersedes / relates-to it. Returns a signed list of edges plus the distinct neighbour fact CIDs (`objs` for out, `subjs` for in); the receipt commits the returned edge CIDs into its signature preimage. When to use: Call this to read the typed CONNECTIONS of a fact — what disagrees with it, what superseded it, what relates to it — as of a point in time. A plain recall gives you the fact; this gives you how that fact links to others in the memory graph. Ask it when the user says 'what is this related to', 'what replaced this observation', 'why is this value contested', or 'what did this place's relations look like as of date X'. Pick a direction: set `subj` (direction="out") to ask 'wha
as_of_tslotintegerValid-time bound. Returns the latest edge per neighbour whose [valid_from, valid_to) interval covers this tslot; supersession keeps the newest edge. Omit for all edges regardless of valid-time.directionstringTraversal direction. "out" (default) = subj→objs; "in" = obj→subjs. Inferred from which of subj/obj you set when omitted; an ambiguous (both set) or empty (neither set) request is rejected with an honest error, never a silent empty.limitintegerMax edges to return.objstringObject fact CID (reverse, direction="in"): edges TERMINATING at this fact ("what points at this fact" — what disagrees-with / supersedes / relates-to it) are returned. Set exactly one of `subj` or `obj`.predstringPredicate filter (e.g. `replaced_by`, `disagrees_with`, `supersedes`, `co_located_with`). Empty string (default) scans every predicate for the anchor fact.subjstringSubject fact CID (forward, direction="out"): edges ORIGINATING at this fact ("what does this fact point at") are returned. Set exactly one of `subj` or `obj`.
emem_fetch1 paramFetch a fact by its content-address (CID). Returns the full signed Primary or Absence fact — the same body served by REST `/v1/facts/{cid}`. Closes the citation loop: any fact_cid surfaced by recall, materialize, attest, or verify can be re-resolved by another agent without REST. When to use: Call whenever you have a `fact_cid` (e.g. from `emem_recall`'s response, an `emem_attest` receipt, an `emem_materializers` outcome, or a citation in another agent's reply) and need the full fact body — its value, unit, sources, signer, signed_at, and derivation. Particularly useful for verifying that a citation a downstream agent gave you actually resolves on this responder. The response is byte-identical across responders for the same CID — the CID itself is the validator.
cidstringrequiredContent-address of any persisted fact (Primary or Absence). Returned by every recall, attest, materialize, and verify call as `fact_cid` / `fact_cids`.
emem_backfill5 paramsMaterialize and sign every per-tslot fact for one (cell, band) inside a [start_unix, end_unix] window. Returns a signed list of (tslot, fact_cid, status) for each step. Slow but possible — one upstream fetch per tslot, capped by `max_facts`. When to use: Call when the user wants HISTORY for a fast/medium-tempo band and `emem_trajectory` returned only the latest point. The responder iterates the tslot range derived from the band's tempo, calls the per-tslot historical materializer, signs each result, and persists. After completion `emem_trajectory` over the same window returns the full series. Bands without a historical materializer (e.g. `weather.*` from met.no's nowcast) return `status: "present_only"` for past tslots — check `emem_coverage_matrix.history_available_from`/`history_available_to` to see how far back each band can be backfilled. Prefer this over staking an attestation when the upstream is publicly fetchable.
bandstringrequiredBand key. Must be a band whose materializer supports historical fetch — see `emem_coverage_matrix` field `history_available_from`/`history_available_to`.cellstringrequiredcell64 or place name (auto-resolved).end_unixintegerWindow end as Unix epoch seconds (UTC). Defaults to now.max_factsintegerCap on number of facts materialized in one call.start_unixintegerWindow start as Unix epoch seconds (UTC). Defaults to the band's `history_available_from`.
emem_heat_solve3 paramsForward-step 2-D explicit finite-difference solver for the heat equation ∂u/∂t = α∇²u over a 3×3 cell stencil centred on `cell`. Reads `modis.lst_day_8day` (Land Surface Temperature) at the centre and 8 cell64 neighbours, integrates N hours ahead under a CFL-stable timestep, returns a signed forecast. Real PDE rollout — not a decay-scoring heuristic. When to use: Use when the user wants a short-horizon LST forecast (urban heat island, surface-temperature evolution, heatwave onset modelling) at a specific cell. Default α=1e-6 m²/s matches urban surface diffusivity (Oke 2017); pass a smaller α for water bodies or higher for vegetated surfaces. The solver caps at one-week horizons because the 8-day MODIS composite stops being a representative initial condition past that. Each call materialises 9 MODIS facts (one per neighbour) on miss — first call ~5 s cold, ~30 ms warm. Receipt cites all 9 input fact CIDs.
cellstringrequiredcell64 string. Forecast LST evolution at this cell.diffusivity_m2_per_snumberThermal diffusivity α (m²/s). Default urban surface (Oke 2017 §2.3); use ~5e-7 for vegetation, ~1.4e-7 for water.hours_aheadnumberForecast horizon in hours; capped at 168 (one week).
emem_wave_solve4 paramsForward-step 1-D explicit finite-difference solver for the shallow-water wave equation ∂²u/∂t² = c²∂²u/∂x² with c² = g·h, where depth h comes from `gmrt.topobathy_mean` along the seaward gradient. Models how an offshore swell of height H_s and period T propagates toward `coastal_cell`. Returns arrival height + time + depth + phase-speed profiles, all under a CFL-stable timestep. When to use: Use when the user wants to predict swell arrival at a coast (storm-surge planning, shoreline-impact assessment, surf forecasting). The solver walks `n_offshore_cells` cells seaward from `coastal_cell` along the bathymetric gradient (default 8 cells = 80 m of profile at the active 10 m grid), samples GMRT depth at each, and integrates the wave equation forward until the wavefront reaches the coast plus one period. Receipt cites every depth fact CID along the profile. Returns 422 with a clear message if `coastal_cell` is land-locked.
coastal_cellstringrequiredcell64 of the coastal destination.n_offshore_cellsintegerCells to sample seaward when building the bathymetric profile.offshore_height_mnumberrequiredOffshore significant wave height H_s (m).period_snumberrequiredWave period (s); typical wind-wave + swell envelope is 6-18 s.
emem_jepa_predict4 paramsPredict next-month NDVI at a cell using a constrained JEPA-pattern AR(2) seasonal predictor. Reads up to 24 past months of `indices.ndvi`, fits a closed-form predictor `y_{t+1} = α·(lag-12 NDVI or recent mean) + β·(last + slope) + γ·recent_mean`, returns the prediction clamped to NDVI's physical range. Coefficients (α=0.6, β=0.3, γ=0.1) are NOT learned — they're fixed from the agricultural-NDVI literature. v2 (future) will train an actual encoder + predictor on the geotessera embedding pool. When to use: Use when the user wants a one-month-ahead NDVI forecast at a specific cell (crop-stress monitoring, growing-season tracking, vegetation-anomaly anticipation). Lookback defaults to 6 months; if fewer monthly tslots are attested at this cell, the predictor uses what's there and surfaces the count in `lookback_months_used`. Returns 422 if no NDVI history exists at the cell — chain to `emem_backfill` first to seed history. Receipt cites every input NDVI fact CID.
bandstringBand to forecast. v1 supports 'indices.ndvi' only.cellstringrequiredcell64 to forecast at.forecast_horizon_monthsintegerHorizon in months ahead. v1 supports 1 only.lookback_monthsintegerHow many past months of history to read.
emem_jepa_predict_v21 paramPredict the next-step value of 4 environmental scalars at a cell — `indices.ndvi`, `modis.lst_day_8day`, `modis.lst_night_8day`, `cams.pm25` — using a small learned dynamics MLP. Reads up to K=6 most-recent attested lags per band, runs them through an ONNX dynamics head (~200k params, CPU-fast), and returns a per-band {value, confidence, n_real_lags, via}. The receipt's `model` block carries `model_id`, `version`, `blake2b_hex` (model_cid), training/validation provenance, a top-level `skill_vs_persistence` block, and `honesty_warnings` — flagging `untrained_baseline` when the artifact is the zero-init sentinel and `NEGATIVE_SKILL` when the learned model is worse than persistence on real held-out NDVI. When the model does not beat persistence, bands with a real lag are returned from that lag tagged `via:persistence_fallback_negative_skill` (bands with no real lag fall back to labelled climatology). Distinct from v1 (`emem_jepa_predict`) which returns a single NDVI scalar via closed-form
cellstringrequiredcell64 to forecast at, or a free-text place name (auto-resolved via /v1/locate).
emem_verify3 paramsVerify a structured claim against a cell's facts. Returns verdict + evidence CIDs + signed receipt. When to use: Call when the user asks a yes/no question about a cell ('is the NDVI > 0.7 here', 'has this been deforested'), or when downstream code wants citable evidence for a logical predicate.
cellstringrequiredclaimobjectrequiredmodestring
emem_bandsActive band ontology (offsets, dims, tempo, privacy). When to use: Call once at session start to learn the band registry — every other primitive's `band` argument MUST come from this list.
emem_functionsActive function registry (derivation recipes). When to use: Call when you need to know which derivative ops are available for `emem_diff` or how a band is computed from upstream sources.
emem_sourcesActive source-connector registry (URL templates, providers, licenses). When to use: Call when you need to inspect which upstream EO providers are wired (Copernicus DEM, JRC GSW, ESA WorldCover, etc.) — useful for license attribution in agent answers.
emem_schemaActive CDDL/JSON schema bundle by CID. When to use: Rarely needed at chat time. Useful for offline verification of receipts / attestations against the exact schema version a responder used.
emem_errorsStable error code catalog. When to use: Call to enumerate the wire-stable error codes — useful when the LLM wants to programmatically branch on responses.
emem_manifestsActive manifest CIDs (bands / functions / sources / schema). When to use: Call to learn which exact registry versions a responder is serving. Cite these CIDs alongside any answer where reproducibility matters.
emem_capabilitiesLive capability snapshot of the responder's GPU sidecar — extensions[] (e.g. gpu, clay-v1.5, prithvi-eo2), cuda_available, models_loaded[], healthy, last_polled_unix_s. Refreshed every 30 s by a background poller; reads are constant-time. When to use: Call before scheduling a GPU-heavy plan (Clay / Prithvi / Galileo embeddings, foundation-anchored algorithms) so the agent knows whether the GPU tier is up *right now* without per-request /health round-trips. Pair with `emem_topics` (its `algorithm_availability` map says which algorithm keys can run given the current capabilities) and `emem_explain_algorithm` (full inference-tier metadata per algorithm). When `extensions[]` is empty the sidecar is unreachable — only CPU/scalar/cached tiers will produce facts; foundation-anchored materializers will sign Absence with `gpu_unavailable` reason.
emem_grid_infoActive grid encoding: cell64 ground resolution, lat/lng axis sizes, DGGS lineage. When to use: Call once at session start (or when the user asks about cell resolution / 'how big is a cell'). Returns the actual ground resolution today (~9.54 m × 9.55 m square at the equator (lat 21 bits × lng 22 bits, matching Sentinel-1/Sentinel-2 native pixel pitch). The cell64 bit layout reserves a resolution-tag field for future hierarchical refinement targeting H3-equivalent res-13 (~3.4 m) cells in v0.1.) and the spec target. Useful before you reason about whether one cell is enough or whether you need `emem_recall_polygon`.
emem_coverage_matrixPer-band live status — what data is alive AND auto-materializable, with history bounds, tempo cadence, and the responder pubkey that signs the band. When to use: Call BEFORE `emem_recall` when you don't know which bands answer at this responder. For each band returns `has_materializer` (true → an empty recall will auto-fetch+sign, no seeding needed), `facts_count` (how many cells already cached), `last_attested_unix_s` (freshness), `tempo_seconds` (slot duration), `history_available_from` / `history_available_to` (oldest/newest Unix epoch the materializer can fetch — use these to bound an `emem_backfill` request), and `responder_pubkey_b32` (the ed25519 key whose signature attests this band — use to detect federation / multi-responder setups). Bands with `has_materializer=false AND facts_count=0` are cube placeholders without a wired connector — don't bother recalling them.
emem_materializersAuto-fetch registry: which bands the responder will materialize on a recall miss, the upstream provider, license, value shape, and history bounds. When to use: Call once at session start (alongside `emem_bands` and `emem_coverage_matrix`) to learn which bands answer for ANY cell on Earth without seeding. Each entry declares `upstream_scheme`, `upstream_endpoint`, `derivation_fn_key`, `value_kind` (primary | absence | primary_or_absence), `coverage` (where the upstream has data), `unit`, `tempo`, `confidence`, and `history_available_from` / `history_available_to` (when the upstream supports historical fetch via `emem_backfill`). Use this when the user asks 'do you have flood data here', 'what providers feed this', or you need license attribution. The response also carries an `agent_hint` block explaining the trust model (responder signs, not upstream) and the absence-fact contract.
emem_data_availabilityTemporal catalog: for every materializable band the upstream-of-record window the data genuinely covers, the temporal `kind` (static | annual_snapshot | annual_stack | time_series | now_only | per_release), tempo seconds, upstream wire path, and whether `emem_backfill` is meaningful. When to use: Call before `emem_backfill` or any historical recall to check whether a band has a meaningful past at the requested time. Each entry includes `history_available_from_unix` / `history_available_to_unix` (and ISO strings) plus `backfill_supported`. Use this to avoid trial-and-error 422s on now-only bands (`weather.*`) and to enumerate the per-year `geotessera.YYYY` vintages the responder ships. The catalog is driven by the same registry the recall path consults — so what it lists is exactly what materializes.
emem_algorithmsContent-addressed dictionary of composition recipes — formulas that fuse attested band facts (and embeddings) into derived scores, classifications, and similarity metrics. When to use: Call when the user's question is COMPOSITE (flood risk, urban density, water consensus, change-since-2020) rather than a single band readout. Each entry has `kind` (solo | combined | embedding), the input `bands` (assemble one `emem_recall` body from them), the `formula` in plain math, the `output` shape, and a `citation`. The agent applies the formula in-process and quotes the algorithm key + `algorithms_cid` (from `emem_manifests`) alongside the input fact_cids — that gives the receipt enough context for any other operator to replay the same composition deterministically. Embedding entries (cosine, novelty, change, neighborhood-consistency) operate on `geotessera`; for the most common k-NN pattern the protocol-native `emem_find_similar` is faster than fetching vectors and computing locally.
emem_explain_algorithm1 paramPer-key drill-down on a single composition recipe — full body (kind, inputs, formula, output, citation, references) for ONE algorithm key. Companion to `emem_algorithms` (which is the catalog). When to use: Call when you already know the algorithm key (from `emem_algorithms`'s catalog or the topic registry) and need its full math. Cheaper than fetching the 190 KB catalog when you only need one entry. Returns the same structure that `/v1/algorithms/{key}` does. 404s with `cid_not_found` if the key isn't registered — call `emem_algorithms` for the live key list.
keystringrequiredAlgorithm key including version suffix, e.g. `walkability_score@1`. Get the live key list from `emem_algorithms`.
emem_topicsTopic-grouped registry of every band and algorithm at this responder, plus visual surfaces and the `declared_but_no_materializer_at_this_responder` block (cube slots reserved without a live connector). Single source of truth shared with `/v1/locate`'s `data_at_this_cell` block. When to use: Call when the user's question lives in a topic but they haven't named a specific band — e.g. 'is this place flood-prone' (→ flood_history_long_term + flood_water_event_window) or 'how walkable is this' (→ urban_livability). Returns three blocks: `live_bands_by_topic` (every band you can recall right now), `algorithms_for_topic` (named recipes that compose those bands into derived answers — pair with `emem_algorithms` for the formulas), and `declared_but_no_materializer_at_this_responder` (honest gaps). Browse here BEFORE inventing your own synthesis formula.
emem_coverage_mapLive SVG render of the responder's corpus density, returned as a proper MCP EmbeddedResource content block (image/svg+xml) — multimodal MCP agents can render it natively. When to use: Call when the user asks 'where do you have data?', 'show me the coverage', or wants a visual brief of the responder's corpus footprint. Returns a 1440×720 Plate-Carrée SVG (1° × 1° bins, log-scale colour, continent envelopes for orientation) plus a structuredContent summary (cell_count, total_facts, responder pubkey, REST URL). Multi-content-block reply: an EmbeddedResource (mimeType `image/svg+xml`, with text + uri) followed by a one-line text summary so text-only clients still see the cell / fact counts. For the bare image bytes, fetch `/v1/coverage_map.svg` over plain REST.
emem_cell_scene_rgb3 paramsTrue-colour Sentinel-2 L2A RGB thumbnail centred on a cell. PNG returned as a native MCP ImageContent block (mimeType image/png). Pure-Rust pipeline: STAC search + HTTP-Range COG reads + 2-98 percentile stretch + PNG encode. When to use: Call when the user wants a VISUAL of a place — 'show me what this looks like', 'before/after the flood', 'is there a forest here', 'is this developed'. Returns a 256×256 px RGB image (~2.56 km × ~2.56 km at S2's 10 m native resolution), centred on the cell. Pass `cell` as a cell64 string OR a place name (auto-resolved). `max_cloud` filters scenes by `eo:cloud_cover` (default 20 %); raise it (60–80 %) for cloud-prone tropics if you keep getting 'no scene' errors. `datetime` is an RFC 3339 interval like `"2024-01-01T00:00:00Z/2024-12-31T00:00:00Z"` for a temporal slice (defaults to last 90 days). `structuredContent` carries the STAC item id, capture time, cloud_cover, EPSG, and per-channel reflectance percentile stretch values used — quote those alongsi
cellstringrequiredcell64 or place namedatetimestringRFC 3339 interval; defaults to last 90 daysmax_cloudnumbermax eo:cloud_cover percent
emem_cell_geojson1 paramCell polygon as a native MCP EmbeddedResource (mimeType application/geo+json). Properties carry centre lat/lng, bbox, approx size in metres, and the 8-cell neighbourhood — drop straight into Mapbox / Leaflet / Deck.gl / QGIS without a GIS pipeline. When to use: Call when the agent (or a downstream renderer) needs the cell as geographic geometry — for map overlays, polygon-clipping ops, or feeding a styling pipeline. Pass `cell` as cell64 or place name. The result is a GeoJSON Feature with Polygon geometry; for a FeatureCollection that includes every recalled fact's value as a property, fetch /v1/cells/{cell64}/recall_geojson?bands=... over plain REST instead.
cellstringrequiredcell64 or place name
emem_recall_many4 paramsRecall facts across a list of up to 256 cell64 strings in one signed envelope. Server fans out per-cell recalls in parallel, then aggregates the response. Auto-materializes any cell with a missing fact whose band has a registered materializer — same contract as emem_recall. When to use: Use after emem_find_similar (give it the neighbour cells), after emem_recall_polygon (when you want a deterministic cell list rather than a polygon), or whenever you have a precomputed set of cells (e.g. an admin-2 sample frame) and want one round-trip. Pass `cells: [c1, c2, ...]` plus the same `bands` shape as emem_recall. For more than 256 cells, batch the call.
bandstringOptional single band override (alias for bands:[band]).bandsarrayOptional band filter — same shape as emem_recall.bands.cellsarrayrequiredList of cell64 strings, max 256. Each cell is recalled in parallel and the responses are merged into a single signed envelope.tslotintegerOptional tslot offset.
emem_elevation4 paramsOne-shot elevation answer that fuses Cop-DEM 30 m (land), GMRT (ocean topobathy), and ESA WorldCover (water mask) into a single signed scalar at a place or coordinate. Returns `elevation_m`, the source actually used, and a `coherence_note` when the two surfaces disagree at the coast. When to use: Use when the user asks 'how high is X' or 'what's the elevation at this lat/lng' and you want the correct answer regardless of whether the cell is land, water, or coastline — the handler picks Cop-DEM for land and GMRT for water and surfaces the choice. Pass `place` (free text), `lat`+`lng`, OR `cell`. Otherwise, prefer emem_recall with `copdem30m.elevation_mean` / `gmrt.topobathy_mean` individually.
cellstringcell64 string — skip geocoding entirely.latnumberWGS-84 latitude.lngnumberWGS-84 longitude.placestringFree-text place name. Resolved through the standard locate cascade. Provide this OR `lat`+`lng` OR `cell`.
emem_fleetPer-band satellite-and-sensor fleet inventory — names the upstream platform (e.g. Sentinel-2A/B, MODIS Aqua/Terra, Landsat-8/9), revisit cadence, native resolution, and license for every materialized band. Lets an agent attribute imagery products correctly and pick the right band when revisit cadence matters. When to use: Call when the user asks 'which satellite is this from', 'what's the revisit time', or needs source attribution for a derived answer. Pair with emem_materializers for the wire path and emem_sources for the connector-level metadata.
emem_temporal_route5 paramsTurn a time-shaped question into a ready-to-run recall plan: it figures out WHICH bands to pull at WHICH past time windows (e.g. 'the year before the flood', 'last growing season', 'two vintages to compare') so you don't have to compute tslot offsets by hand. Returns the band + lookback + a `purpose` tag for each step. When to use: Call this first when the user's question is about CHANGE OVER TIME or a PAST EVENT and you're not sure which bands/dates to recall — 'was this flooded last year', 'what was the NDVI baseline before the fire', 'compare this place across vintages'. It hands you the recipe; then run those steps with `emem_recall`. Skip it when the user wants a single current reading. Pass `cell` plus an optional free-text `intent` hint. The plan is deterministic and the receipt cites which algorithm supplied each step.
bandsarrayOptional band filter to scope the planner.cellstringrequiredcell64 to plan a temporal recall over.intentstringOptional intent hint — drives recipe selection (e.g. 'flood_window', 'crop_season', 'change_year').limitintegerOptional cap on recipe entries returned.query_timeintegerOptional anchor time (Unix epoch seconds). Defaults to now.
emem_verify_receipt2 paramsVerify a signed receipt envelope server-side: recomputes the canonical preimage (`request_id | served_at | primitive | cells, | fact_cids,`), runs ed25519 over the embedded pubkey + signature, and returns `{valid, reason, pubkey_b32}`. Use when the in-browser /verify path is blocked (CDN offline, agent runtime has no crypto) or when you want a server-side audit of a third-party receipt. When to use: Pass a receipt object exactly as returned by any read primitive (signature can be byte[] or sig_b32; pubkey can be byte[] or responder_pubkey_b32 — the verifier tolerates both shapes). Optionally override `pubkey_b32` to assert verification against a specific signer. Returns 200 with `valid: false` when the signature fails — never 4xx for a structurally-well-formed bad signature.
pubkey_b32stringOptional explicit responder pubkey (base32). When omitted, uses the receipt's embedded pubkey/responder fields.receiptobjectrequiredThe signed receipt envelope (as returned by any read primitive). Must carry primitive/served_at/request_id/cells/fact_cids and either `signature` byte[] + `responder_pubkey` byte[] or their b32 string forms.
emem_at8 paramsOne-shot multi-band recall at a place (or lat/lng). Defaults to emem's standard at-a-glance band set; pass `band` / `bands` to override. Polygon-resolved places stay at the centroid by default (`n_cells: 1`) to keep multi-band calls cheap — pass `n_cells: 2..=64` to fan out. When to use: Use when the user names a place and wants the standard situational readout (vegetation + elevation + landcover + recent weather) without picking bands. Polygon-aware: `place` that resolves to a polygon (park, lake, district) lands at the centroid unless `n_cells` widens it. For a single band, use the domain-specific shortcuts (emem_ndvi, emem_air, …) or emem_recall directly.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_ndvi8 paramsRecall Sentinel-2 NDVI (indices.ndvi, 10 m native) at a point or place. Composes locate → cell64 → recall in one call; auto-materializes on miss. When to use: Use when the user names a place (or lat/lng) and just wants the NDVI number. Polygon-resolved places default to a 16-cell fan-out aggregated as mean/median. Set `n_cells: 1` for point behaviour. For multi-band batches use emem_recall.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_air8 paramsRecall Copernicus CAMS air-quality bands at a place: PM2.5 + NO2 + O3. Composes locate → recall → aggregate. When to use: Use when the user names a place and asks about air quality, pollution, or emissions exposure. CAMS is the European reanalysis — global coverage, ~0.4° native (resampled). For finer-grained urban PM2.5, pair with /v1/at-style stations data when available.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_lst8 paramsRecall MODIS land surface temperature day-8day + night-8day composites at a place. 1 km native, 8-day composite. When to use: Use when the user asks about surface heat, urban heat island, thermal anomalies, or wants day/night LST. Returns both fluxes so the agent can derive day–night spread.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_soil8 paramsRecall SoilGrids 250 m profile at a place: SOC, pH, clay/sand/silt fractions, bulk density, nitrogen — all at 0–30 cm depth. When to use: Use when the user asks about soil quality, agricultural suitability, or carbon stocks at a location. Six bands returned in one envelope.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_water8 paramsRecall surface-water signals at a place: JRC Global Surface Water recurrence (1984–2021) + Sentinel-1 SAR backscatter (current). Pair detects standing water through clouds. When to use: Use when the user asks about flooding, wetlands, surface-water dynamics, or wants a robust water-presence check. JRC alone gives historical baseline; Sentinel-1 gives current flood detection.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_forest8 paramsRecall forest signals at a place: Hansen Global Forest Change (tree cover 2000 baseline + year-of-loss) + ESA WorldCover 2021 land class. When to use: Use when the user asks about deforestation, canopy cover, forest loss, or wants a forest-vs-not classification. Hansen gives year-of-loss for any cell with disturbance since 2001; WorldCover gives the current land class.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_weather8 paramsRecall the standard met.no/CAMS weather bundle at a place: 2 m temperature + total cloud cover + precipitation + 10 m wind speed. When to use: Use when the user names a place and asks 'what's the weather' or wants a now-cast snapshot. weather.* bands are now-only (no backfill); for climatology use terraclimate.*.
bandstringOptional single band override — replaces the endpoint's default band set with this one.bandsstringOptional CSV of band keys — replaces the endpoint's default band set.includearrayOpt-in heavy response sections. Default response omits per-cell arrays to stay under MCP's 25 KB cap. Name specific sections to include them.latnumberWGS-84 latitude. Paired with `lng`. Use when you already have coordinates.lngnumberWGS-84 longitude. Paired with `lat`.n_cellsintegerPolygon fan-out width. `n_cells: 1` = point at centroid. Defaults vary per endpoint (1 for /v1/at, 16 for single-band endpoints).placestringFree-text place name. Resolved through the standard /v1/locate cascade (wide-bbox → embedded → GeoNames → cache → Photon → Nominatim). Provide this OR `lat`+`lng`.tslotintegerOptional tslot offset (band-tempo-relative).
emem_intent10 paramsSubmit a typed Intent; receive a plan or executed result. When to use: Call when the user asks something like 'where is X' or 'is A like B' and you don't want to pick a primitive yourself — the planner maps Intent variants to the right tool call.
astringbstringbandstringcellstringclaimobjectdescriptionstringkintegerkeystringtypestringrequiredwindowarray
README.md
emem
Earth as memory, for real-world agents.
Hosted · Docs · Spec · OpenAPI · Try it · /verify · Gallery · HF Space
Ask an AI agent what is on the ground at 19.07° N, 72.87° E and it will guess. It has no fixed handle for that patch of Earth, and no way to prove whatever number it returns. emem is the handle. It is a shared memory of the planet that an agent can read, write, and cite, where every answer is signed so anyone can check it later without trusting the server that produced it.
The planet is cut into fixed cells about 9.55 m across, the way a page is cut into words. One measurement at one cell is a fact: an elevation, a rainfall total, this year's forest loss, a satellite embedding. Every fact is signed. When an agent asks about a place nobody has measured yet, the responder pulls the value from a real satellite source, signs it, and hands it back in the same response. Nothing is pre-seeded. Every cell on Earth answers from the first request.
emem is a protocol. A fact is named by the blake3 hash of its own bytes, so the name carries the data's fingerprint and means the same thing on every machine. The responder signs that name with an ed25519 key, the kind that secures SSH and HTTPS. Any responder can serve a fact and any client can verify it offline, with no account and no key to manage. Paste a fact id into a chat and a colleague pulls the same bytes from any node and checks the signature in their own browser at /verify. The hosted node is https://emem.dev. The same binary self-hosts with one docker run, and the same handlers answer both MCP and plain REST. Run enough nodes and you get a federation: independent responders that resolve the same ids byte for byte and write down where they disagree. The memory gets more trustworthy as more agents use it.
How a fact gets made and proven
A cell64 addresses a place the way a token addresses text in an LLM. Every patch of ground about 9.55 m wide gets a 64-bit id, and ids that look alike sit physically near each other. A fact is one measurement at that cell, keyed by (cell, band, time) and packed in a fixed byte order (canonical CBOR) so the same reading hashes the same way on every machine. That blake3 hash is the fact's content id. Change one byte and the id changes, so the id proves the bytes. The responder signs it. The signed envelope it returns is the receipt, and the receipt checks out offline against the responder's public key without any trust in the server.
When an agent asks for a band at a cell that has no signed fact yet, the responder fetches the underlying tile through one of its 46 upstream sources, signs the result under its own key, persists it, and returns it in the same response. A cold read takes about 180 ms. A warm read is under ten. Five of the 46 schemes are declared but not yet wired (openet.30m.daily, dynamic_world.v1, tropomi.s5p.ch4, tropomi.s5p.no2, viirs.dnb.monthly); they answer with a typed Absence. When a band genuinely has no value at a cell, because the place is outside coverage or the upstream is unreachable, the answer is still a signed absence with a reason you can read. An empty answer is a citable receipt. The catalog never promises more than it can sign.
Try it (no install, no key)
# Geocode a place to a cell64.
curl -s -X POST https://emem.dev/v1/locate \
-H 'content-type: application/json' \
-d '{"q":"Bengaluru"}' | jq .cell64
# "defi.zb493.xuqA.zcb5f" # (geocoder result, may drift)
# Recall a band at that cell (auto-fetched if cold).
curl -s -X POST https://emem.dev/v1/recall \
-H 'content-type: application/json' \
-d '{"cell":"defi.zb493.xuqA.zcb5f","bands":["weather.temperature_2m"]}' \
| jq '.facts[0]'
# Ask a free-text question; the foundation-embedding fan-out fires
# automatically on "find places like" / "what changed" intents.
curl -s -X POST https://emem.dev/v1/ask \
-H 'content-type: application/json' \
-d '{"q":"find places like Yellowstone","place":"Yellowstone National Park"}' \
| jq '.answer'
# Hunter mode: discover event hotspots over a named region. The same
# classifier reads "find <event> in <region>" from /v1/ask and routes
# here; structured callers can hit /v1/hunt directly.
curl -s -X POST https://emem.dev/v1/hunt \
-H 'content-type: application/json' \
-d '{"event":"algal_bloom","region":"Lake Erie"}' \
| jq '.hotspots[0]'
The receipt's fact_cid is a durable handle. Re-fetching it from any responder, in any year, returns the same bytes.
Verify an answer (four curls)
The pitch lives or dies on this flow. Every recall response carries a receipt with fact_cids[], a merkle_proof, and an Ed25519 signature over a domain-separated, length-prefixed preimage: blake3("emem.preimage.v1" ‖ "receipt" ‖ tagged(request_id, served_at, [scope], [as_of], [edges], [manifest], primitive, cells[], fact_cids[])). Tagging every field and prefixing its length means no two distinct responses can ever share signed bytes; the receipt's preimage_version selects the rule, and pre-v1 receipts still verify under the original one. The signer's public key is stable; the receipt verifies offline against any copy of the responder pubkey. The merkle tree uses RFC 6962 leaf/node domain separation and rejects duplicate leaves.
Here is a real one. Ask https://emem.dev for the elevation under Denver and it returns the city's nickname as a signed number, mile-high at 1609 m, which anyone can re-check without trusting the server:
// POST /v1/recall {"cell":"defi.zb5c4.guxe.nuxe","bands":["copdem30m.elevation_mean"]}
{
"facts": [{ "cell": "defi.zb5c4.guxe.nuxe", "band": "copdem30m.elevation_mean",
"value": 1609.0, "unit": "m", "source": "copernicus.dem.glo30" }],
"receipt": {
"primitive": "emem.recall",
"fact_cids": ["72wdchiyurfrjxz7zat6kor7gjnvsn564fbrzjkmlhagoy4rrh4a"],
"responder_pubkey_b32": "777er3yihgifqmv5hmc2wwmy…",
"preimage_version": 1,
"signature": "…ed25519 over the canonical preimage…"
}
}
Paste that fact_cid into /verify and the page re-derives the hash and checks the signature in your browser. The four curls below do the same from a shell:
# 1. Resolve a place to a cell64.
CELL=$(curl -s -X POST https://emem.dev/v1/locate \
-H 'content-type: application/json' \
-d '{"q":"Golden Gate Park, San Francisco"}' | jq -r .cell64)
# 2. Recall a band and capture the receipt envelope.
curl -s -X POST https://emem.dev/v1/recall \
-H 'content-type: application/json' \
-d "{\"cell\":\"$CELL\",\"bands\":[\"indices.ndvi\"]}" > /tmp/recall.json
jq '.receipt | {primitive, served_at, responder_pubkey_b32, fact_cids, merkle_proof: .merkle_proof.root}' \
/tmp/recall.json
# 3. Ask the responder to verify its own signature (server-side check).
jq '{receipt: .receipt}' /tmp/recall.json > /tmp/receipt.json
curl -s -X POST https://emem.dev/v1/verify_receipt \
-H 'content-type: application/json' --data @/tmp/receipt.json
# {"valid":true,"preimage_blake3_hex":"…","fact_cids_count":1,"signer_pubkey_b32":"…",…}
# 4. Reproduce: pull the same fact_cid from any responder, on any day.
# The cell, band, tslot, and derivation.fn_key are content-addressed, so
# the bytes you receive will hash to the same fact_cid.
jq '.facts[0].derivation' /tmp/recall.json
For a browser-only verify, open /verify/<fact_cid>; the page does the same Ed25519 check in WebCrypto + @noble/ed25519 so you never have to trust the responder you got the receipt from. A guided walk lives at /demos/signed-answer.
Architecture
One binary. The same handlers answer MCP and plain REST, reads need no auth, and every write lands in an append-only signed log. Four content-addressed manifests (bands_cid, algorithms_cid, sources_cid, schema_cid) pin exactly what produced each answer. The full deployment suite lives at /docs/diagrams.
The memory layer
A cache hands back a tile. A memory remembers what it saw, links it to what it saw before, and says so when two sources disagree. emem gives an agent that second thing on top of the fact store, and the agent owns it.
An agent's memory of Earth, drawn as an engram. Each cell is a node and each edge a synapse that relates, supersedes, or disagrees. Recall draws signed facts inward to the lotus where the shared memory consolidates, and every node carries its own signature.
Writes land in /memories/ as content-addressed, signed files. memory_create makes one, memory_str_replace and memory_insert edit it, and memory_search runs a BGE-768 embedding query over the contents through a LanceDB IVF_PQ index, so an agent finds a note it wrote last week by meaning instead of by filename. Each file carries a kind from the CoALA taxonomy: episodic for what happened, semantic for what holds true, procedural for how to do a thing, resource for a pointer out. A write under /memories/by_attester/<pubkey>/ is capability-bound, so a path owned by one key turns away every other signer. The signature that proves a Sentinel-2 reading is the same signature that proves the agent's own notes are untouched.
The memory connects facts and notices when they fight. memory_bundle folds N facts into one signed envelope, memb:<bundle_cid>, that resolves to identical bytes on any peer, so an agent hands over a single citation for a whole finding instead of a list of loose ids. memory_contradictions walks the cases where two attesters signed different values at the same (cell, band, tslot) and scores the gap by band kind: normalised spread for a scalar, mean cosine for a vector, mode-share for a category. A second node that read the same Sentinel scene on a cloudier day leaves a trace the agent can weigh instead of a silent overwrite.
Every read takes a bi-temporal bound. as_of_tslot asks what the world looked like at a past moment. as_of_signed_at asks what the system knew at a past moment. Set both and both hold. The receipt records the bound, so an auditor in 2027 takes a 2026 receipt to any peer and replays the exact same query.
Streams
The memory is live, and you can watch it. GET /v1/stream is a Server-Sent Events heartbeat. Every few seconds the responder signs a snapshot of corpus state and pushes it, so a dashboard or an agent follows the shared memory growing without polling for it. The tick is signed like everything else, captured here straight off https://emem.dev:
event: state
data: {
"type": "corpus.state",
"served_at": "2026-06-12T16:17:30Z",
"corpus": { "distinct_cells": 8147, "distinct_bands": 75, "facts_scanned": 32768 },
"responder": { "pubkey_b32": "777er3yihgifqmv5hmc2wwmy…", "key_epoch": 0 },
"signature": {
"alg": "ed25519",
"preimage": "emem.stream.tick|v0.1.0|epoch0|2026-06-12T16:17:30Z|registry:3pbqnyni…|cells:8147",
"signature_b32": "xk2hiluwmfywwnfj…"
}
}
GET /v1/memory/sse?path_prefix=&kind=&attester= is the narrow stream. It pushes one event the moment a memory write commits, filtered server-side, so a compliance subscriber sees a write to a watched path the instant its sled commit lands rather than on the next poll.
Connect your AI assistant
The MCP endpoint is https://emem.dev/mcp. Drop a config snippet into your client.
| Client | Config |
|---|---|
| Claude Desktop | examples/claude-desktop.json |
| Claude Code | examples/claude-code.mcp.json |
| Cursor | examples/cursor.mcp.json |
| Cline (VS Code) | examples/cline.mcp.json |
| Gemini CLI | gemini extensions install https://emem.dev/gemini-extension.json |
| ChatGPT (Custom GPT) | examples/openai-gpt-action.json |
| LangChain (Python) | examples/langchain.py |
| LangChain MCP agent | examples/langchain/ |
| LlamaIndex (Python) | examples/llamaindex.py |
| LlamaIndex MCP agent | examples/llamaindex/ |
| Agno MCP agent | examples/agno/ |
| Pydantic AI MCP agent | examples/pydantic-ai/ |
| AutoGen MCP agent | examples/autogen/ |
| CrewAI MCP agent | examples/crewai/ |
| Mastra MCP agent | examples/mastra/ |
Python (ememdev) and TypeScript (@emem/client) SDKs live under sdks/ (PyPI / npm publication pending; install from the repo today).
Primitives
81 MCP tools (10 core, 71 extended), 93 documented REST paths under /v1/*, surfaced through /openapi.json. Every tool carries a when_to_use string written for LLM tool-selection, and four MCP behavioural annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint). A no-param tools/list returns all 81 tools (so every MCP client discovers the full surface); pass {"tier":"core"} for just the 10 essentials. Tools are callable via tools/call regardless of tier.
- Locate: name or lat/lng →
cell64. Five-layer cascade: wide-bbox table → embedded gazetteer → GeoNames cities-5000 (68 581 places, in-process) → sled cache → Photon → Nominatim. Polygon geometry from Overturedivisions/division_area. District-level queries reroute through Overture when Nominatim returns a POI courthouse. - Memory substrate (state + tokens + bundles + memory files + search + contradictions + SSE):
POST /v1/statereturns a signed dense per-place embedding (view=encoderdefault 128-D,view=cubefull 1792-D).POST /v1/state_multifans acrossgeotessera+clay_v1+prithvi_eo2+galileo.POST /v1/state_diffreturns residual + L2 + cosine between two vintages.POST /v1/memory_tokencomposesmemt:<cell64>:<fact_cid>.POST /v1/memory_bundlecomposes a signed envelopememb:<bundle_cid>over N (cell, band, tslot) triples. Six MCP file-op verbs (memory_view,memory_create,memory_str_replace,memory_insert,memory_delete,memory_rename) conform to Anthropic's memory-tool spec; every write is ed25519-signed and content-addressed. Paths under/memories/by_attester/<pubkey>/...enforce capability binding (ed25519 signature overblake3("emem.memory_write|" + verb + "|" + path + "|" + body_hash)). Each file carries akindfrom the CoALA taxonomy (episodic/semantic/procedural/resource).POST /v1/memory/searchdoes BGE-768 semantic search over file contents via a LanceDB IVF_PQ partition.POST /v1/memory_contradictionswalks a parallel multi-attester index and scores disagreement per band kind (scalar / vector / categorical).GET /v1/memory/sse?path_prefix=&kind=&attester=streams write events with server-side filter. Every read primitive acceptsas_of_tslot+as_of_signed_atfor bi-temporal queries (valid-time + transaction-time); the receipt carries anas_ofblock when set. Seedocs/memory.mdfor the full reference. - Recall / recall_many / recall_polygon: 124 materializer-wired band names across 43 cube slots. Recall answers any wired band, auto-fetching on a cold miss and signing the result. Signed Absence on out-of-coverage.
- Find similar: k-NN over any vector band. Hamming fast path (sign-bit pop-count) auto-derives from the cosine band when the binary sibling is absent. Mode
hamming_then_reranktriages with Hamming then re-orders by cosine; the over-sampling factor is EWMA-adaptive. - Compare / compare_bands / diff / trajectory: pairwise and time-series.
- Connect & evolve: typed temporal edges (
emem_edges_recallreads a fact's signed connections of typedisagrees_with,supersedes, orrelates_to, bounded by valid-time), multi-attester contradiction scoring (memory_contradictions, per band kind), and a deterministic refinement loop that re-derives a fact when a newer attestation or adisagrees_withedge lands. All three ship in 0.1.0. - Verify: structured claim against attested facts; returns signed verdict + evidence CIDs.
- Physics:
/v1/heat_solve(2-D explicit FTCS heat, MODIS LST stencil),/v1/wave_solve(1-D shallow-water along seaward bathymetry gradient),/v1/jepa_predict(closed-form NDVI AR(2) seasonal),/v1/jepa_predict_v2(Tessera embedding dynamics; short-circuits to last-vintage identity baseline while the trained head is pending, receipt carriesuntrained_baseline). - Ask: free-text question with topic routing. The classifier covers three intent families: place-anchored topical questions (the topic router fan-out), foundation-embedding intents on
find places like/what changed/deforestation/anomaly(cross-encoder consensus over Clay + Prithvi + Tessera), corpus-meta intents onwhere do you have data/how fresh is your corpus(redirect to coverage surfaces), and hunter-mode discovery onfind <event> in <region>(routes to/v1/hunt). - Hunter:
POST /v1/huntand MCPemem_huntfor open-world event discovery. Twelve event keywords (algal_bloom,deforestation,flood_extent,wildfire,urban_heat_island,methane_plume,landslide,drought,soil_salinity,crop_stress,water_turbidity,oil_slick) each map to a registered detection algorithm. The responder samples up to 32 cells from the named region (8 for slow primary bands such as MODIS LST), recalls the algorithm's primary scalar plus any configured gate band (e.g. NDWI > 0 for water-mask events), and returns the top 8 hotspots with cell64, lat/lng, recalled value, gate value, fact CID, and a Sentinel-2 scene URL. A Tessera embedding rerank fires when at least three candidate cells have a geotessera vector available, re-ordering by cosine similarity to the cluster centroid.oil_slickreturnsstatus: not_yet_implementedwith pointers atflood_extent_sar_threshold@1andwater_turbidity_red_band@1instead of fabricating detections. - EUDR Due Diligence Statement:
POST /v1/eudr_ddsand MCPemem_eudr_ddsproduce a signed Annex II-shaped DDS under Regulation (EU) 2023/1115. The per-cell algorithmeudr_compliance@1implements Article 2(4) as written: >0.5 ha, >5 m height, >10 % canopy cover, excluding land predominantly under agricultural or urban use. The verdict is the consensus of two static baselines read with one windowed COG sample per band over the plot: JRC GFC2020 V3 (the Commission's expected non-binding baseline) for forest-at-cut-off, and Hansen GFC v1.12 loss-year for clearing strictly after the 31 December 2020 cut-off. A cell cleared on or before the cut-off isnot_in_scope, never a pass. Plot aggregation applies the Article 2(4) 0.5 ha minimum-mapping-unit floor, and the Article 2(28) dispatch picks POINT (≤4 ha non-cattle) vs POLYGON (>4 ha or any cattle plot under HS 0102/0201/0202). Each plot also carries aloss_year_histogram, the per-year distribution of Hansen loss-year over its sampled cells, signed as its ownforest_change.lossyear_histogramderivative whose id is folded into the receipt, so the loss-year breakdown is a verifiable figure rather than an unsigned summary. JRC TMF, Sims et al. 2025 driver attribution, and RADD Sentinel-1 alerts sit off the verdict hot path (their upstreams do not honour HTTP Range); each stays available as an explicit band request, and the responder will not fabricate a value for a connector it cannot read. Two disclaimers keep the scope honest:legality_disclaimerfor Article 9(1)(b) (land tenure, FPIC, country-of-origin law, structurally out of EO scope), anddegradation_disclaimerfor Article 2(7) forest degradation (the verdict measures deforestation, not degradation). The JSON Schema at/v1/schemas/eudr_dds.jsoncites the exact EUR-Lex paragraph each field maps to;regulation_status_notetracks the application deferral (Regulations 2024/3234 and 2025/2650 → 30 December 2026 for large operators, 30 June 2027 for micro and small). - Domain shortcuts:
emem_at,emem_ndvi,emem_air,emem_lst,emem_soil,emem_water,emem_forest,emem_weather. Collapse locate → recall → polygon-aggregate into one call by place name. - Field boundaries: Fields of The World (~3.17 B field polygons, 241 countries, 10 m, CC-BY-4.0) via PMTiles range reads on
source.coop. - Visual surfaces:
/v1/coverage_map.svg(1440×720 plate-carrée of attested cells, log-scale density) and/v1/places/scene_overlay.svg?place=…&band=…(per-place value-painted bbox grid; band-aware ColorBrewer ramps, horizontal legend, km scale bar, signed source line). The MCP equivalents return the same SVG as anEmbeddedResourceblock. The full set, plus the 32-diagram protocol/industry suite, lives at /docs/gallery and /docs/diagrams.
One use case, end to end. A geolocated plot is checked against the forest baseline and the Hansen loss-year over the 2020 cut-off, the verdict and its per-year loss histogram are signed into one Due Diligence Statement, and that 26-character handle is what clears customs. This is what eudr.dev runs on.
Algorithms
160 named composition recipes (flood_risk@2, walkability_score@1, heat_index@2, carbon_sink_score@1, eudr_compliance@1, forest_carbon_loss_co2_flux@1, enteric_ch4_dairy_tier1_ipcc2019@1, n2o_synthetic_fertilizer_ef1_ipcc2019@1, ...) live in a content-addressed registry. Each carries:
formula: plain math the agent can read and apply.inputs: band keys with role + explanation.when_to_use: agent-targeted trigger guidance.citation: peer-reviewed source.accuracy_band: honest precision estimate, not marketing.parameters: typed tunable thresholds (gate, k, timeout, ...).learned_from: citation provenance for every tuned number. An auditor can trace any gate threshold back to a referee.
Algorithms with an evaluation: Expr AST are also re-executable in-process: the responder walks the AST against the snapshot recall and returns a signed composite scalar that any third party with matching algorithms_cid and input fact CIDs reproduces deterministically.
Browse at GET /v1/algorithms or per-key at GET /v1/algorithms/<key>.
Discovery
Designed for agents to read, not for humans to remember:
GET /openapi.json OpenAPI 3.1 of every REST route
GET /v1/agent_card live capability snapshot + manifest CIDs
GET /v1/tools 81 MCP tools (10 core, 71 extended) with when_to_use + annotations
GET /v1/algorithms?summary=true 160 algorithm keys + categories
GET /v1/topics 27 topic-grouped bands + algorithms (router brain)
GET /v1/manifests bands_cid, algorithms_cid, sources_cid, schema_cid
GET /v1/schemas/eudr_dds.json Annex II JSON Schema with EUR-Lex paragraph citations
GET /.well-known/{emem,agent,mcp,ai-plugin}.json
POST /v1/state signed dense state vector at any cell (view=encoder | view=cube)
POST /v1/state_multi fan-out across geotessera + clay_v1 + prithvi_eo2 with typed missing[]
POST /v1/state_diff vintage delta at one cell: residual vector + L2 + cosine
POST /v1/memory_token compose memt:<cell64>:<fact_cid> citation handle
POST /v1/memory_token/resolve single round-trip dereference back to signed fact body
GET /v1/stream Server-Sent Events corpus heartbeat, signed every 5-300 s
GET /v1/corpus_state_stats signed snapshot of corpus liveness (one-shot equivalent of /v1/stream)
GET /v1/benchmark hand-verified eval items; pair with POST /v1/benchmark/grade
POST /v1/hunt structured event-discovery sweep (12 events × region)
POST /v1/eudr_dds EUDR Due Diligence Statement (Regulation EU 2023/1115)
POST /mcp JSON-RPC 2.0 (Streamable HTTP)
GET /llms.txt /llms-full.txt plaintext catalog for LLM ingestion
GET /humans /humans.json interactive try-it surface + machine twin
GET /verify /verify/<fact_cid> in-browser ed25519 receipt verifier
GET /docs/gallery live coverage map + hunter case studies + 32 diagrams
GET /docs/diagrams/ 32 SVGs of protocol + industry deployments
The operator_attestation block in /.well-known/emem.json binds the running binary's BLAKE3 hash to its git_commit + build_timestamp and signs the triple under the responder's ed25519 key, so a verifier can confirm the live binary corresponds to the published source tree without trusting the operator.
Every receipt pins four content-addressed registry CIDs (bands_cid, algorithms_cid, sources_cid, schema_cid). A peer that recomputes a fact under matching CIDs produces the same bytes. A peer with drifted registries returns a different bands_cid on /health and the divergence is visible before any data flows.
Run it locally
cargo run --release --bin emem-server
# Or via container.
docker run -p 5051:5051 ghcr.io/vortx-ai/emem:latest
No required env vars. EMEM_BIND overrides the listener (default 0.0.0.0:5051). EMEM_DATA overrides the data directory (default ./var/emem; pass :memory: for ephemeral). For TLS, systemd, ACME on :443, and the HuggingFace Space wrapper, see docs/operators/operating.md.
Address algebra
| field | bits | wire form | example |
|---|---|---|---|
cell |
64 | four base-1024 bigrams, dot-sep | defi.zb493.xuqA.zcb5f |
tslot |
64 | base32-nopad-leb128, t. prefix |
t.aaaaagy |
cid |
32 B BLAKE3 | base32-nopad-lowercase, 26 chars | qi3jo4sqcg…l2hgjtwm |
vec |
1792-D fp16 | 12-byte prefix in receipts | full vector via recall |
The active grid is ~9.54 m × ~9.55 m at the equator (lat 21 bits × lng 22 bits, asymmetric to match the 360°/180° ratio). Above the equator, longitude pitch narrows with cos(lat). The Hilbert-ordered base-1024 alphabet keeps adjacent cells string-prefix-similar, so an LLM that emits defi.zb493… already lands in roughly the right place. GET /v1/grid_info declares the active resolution honestly; the spec target is a hierarchical migration toward H3-equivalent res-13 (~3.4 m).
Repo layout
emem/
├── crates/ # 16 workspace crates, MSRV 1.91, version 0.1.0
│ ├── emem-core/ # bands, algorithms, functions, sources, topics, schema
│ ├── emem-codec/ # cell64, cid64, vec64, hilbert, geo, alphabet
│ ├── emem-fact/ # canonical CBOR; fact, receipt, attestation
│ ├── emem-claim/ # claim predicates (Op enum)
│ ├── emem-cache/ # sled cache wrapper
│ ├── emem-fetch/ # 16 data connectors + 13 utility modules
│ ├── emem-storage/ # sled hot cache + append-only merkle log
│ ├── emem-cubes/ # 1792-D voxel cube handle
│ ├── emem-primitives/ # recall, find_similar, trajectory, compare, diff, verify, query_region
│ ├── emem-attest/ # merkle root over fact CIDs
│ ├── emem-intent/ # rule-based intent → plan planner
│ ├── emem-mcp/ # MCP tool descriptor registry (81 tools, core + extended)
│ ├── emem-api-rest/ # axum router, physics solvers, foundation fan-out
│ ├── emem-cli/ # binaries: emem-server, emem-livedemo, emem-realdemo, emem-demo, emem-ask-eval
│ ├── emem-membench/ # memory-substrate benchmark harness
│ └── emem-sleep-agent/ # offline refinement loop over contradictions + edges
├── sdks/
│ ├── emem-py/ # Python client (httpx, sync + async)
│ └── emem-ts/ # TypeScript client (zero runtime deps, native fetch)
├── python/ # FastAPI sidecar over UDS: Prithvi-EO-2.0, Galileo, Clay v1.5, JEPA-v2
├── examples/ # MCP configs + LangChain / LlamaIndex
├── ops/ # systemd units, journald retention
└── web/ # SSR HTML, humans, verify, llms.txt, agent.json
The 16 data connectors back 46 declared source schemes and 124 live materializer registrations. Five of the 46 schemes are declared-but-unwired (openet.30m.daily, dynamic_world.v1, tropomi.s5p.ch4, tropomi.s5p.no2, viirs.dnb.monthly); they return a typed Absence, not data. Most wired schemes route through cog.rs, the universal STAC + COG sampler, plus bespoke modules for chirps (rainfall), dmsp_ols (nightlights), esa_cci_biomass (above-ground biomass, CEDA), firms (active fire), ftw (Fields of The World), geonames (gazetteer), gmrt (topobathymetry, PointServer + GridServer), hansen_gfc (forest change), jrc_gfc2020 (EUDR forest baseline, JEODPP single-COG), jrc_tmf (tropical moist forest, pull-and-cache), koppen (climate classification), overture (places / buildings / divisions), radd_alerts (Sentinel-1 disturbance), terraclimate (climate), wdpa (protected areas), worldpop (population), wri_gdm_drivers (Sims et al. 2025 driver attribution).
Inference
The GPU sidecar (Python FastAPI over Unix domain socket) co-resides four encoders on a 20 GB VRAM budget:
- Clay v1.5: 1024-D CLS, S2 L2A 10 bands, ~12 ms warm. Teacher (DINOv2
vit_large_patch14_reg4_dinov2.lvd142m) pre-staged at boot soHF_HUB_OFFLINE=1holds. - Prithvi-EO-2.0-300M-TL: 1024-D CLS, HLS V2 6-band, ~13 ms warm.
- Galileo (variant
basein production;tiny/nanoselectable viaEMEM_GALILEO_VARIANT): S2-only modality wired (S1 / ERA5 / SRTM / VIIRS / Dynamic-World / WorldCover / LandScan / location zero-masked; the scaffold is multimodal but only S2 is connected today). The advertised capability isgalileo-<variant>in/v1/capabilities.extensions[]. - JEPA v2 dynamics: untrained baseline. Metadata-only
is_trained()check short-circuits to last-vintage identity; receipt carriesuntrained_baselineandvia: "short_circuit_untrained". Training is upstream-bottlenecked on multi-vintage Tessera availability.
Sidecar crash does not cascade. The REST router degrades to scalar bands and signs the GPU-anchored algorithms as Absence with gpu_unavailable. See docs/developers/inference.md.
Where this is going
emem is built to be a protocol, not a single service. Because every fact is content-addressed and signed, any responder can serve it and any client can verify it offline, without trusting the source. Today that runs as one hosted responder plus self-hosted nodes. The design target is a federation of independent responders that resolve the same content ids byte-for-byte, cross-cite each other's attestations, and record where they disagree, so the shared memory gets more trustworthy the more agents read and write against it. None of the multi-host federation routing ships in 0.1.0. What ships today is the substrate that makes it possible: content addressing, signed receipts, typed temporal edges, multi-attester contradiction scoring, and a deterministic refinement loop.
The end state: many responders, one address space. A content id means the same bytes everywhere, every responder signs under its own key, and a client trusts the signature instead of the server. Where two responders disagree, the network records it.
Honest limits
- No commercial sub-meter imagery. Sentinel-2 (10 m), Landsat (30 m), HLS. For Planet Pelican (50 cm) or Maxar bring your own connector.
- No edge / onboard inference. Sidecar runs on a single host.
- Single-host deployment. No federation, no global routing, no SOC 2.
- JEPA v2 is untrained today. The endpoint exists and signs honestly; predictions equal the last attested vintage until the dynamics head is trained.
- 16 data connectors, 124 live materializer registrations. Catalog-by-count is not the pitch; every wired band is auto-fetchable, signed, and content-addressed. Bands without a wired materializer are listed under
declared_but_no_materializer_at_this_responder. - Foundation-encoder materializers are uneven.
geotessera(Tessera 128-D) has a wired materializer and auto-fetches on miss.clay_v1andprithvi_eo2are seed-only at this responder: the GPU sidecar runs both models, but the auto-materialise path that fans out to upstream tile archives is not wired today. Recall against either returns whatever has already been signed; the hunter-mode envelope discloses this per request undermaterializer_status[]. - Tessera is upstream-rate-limited.
dl2.geotessera.orgreliably serves 2024 vintages today; historical backfill across all eight vintages (2017–2024) is partial. The Tessera-coherence rerank in hunter mode gracefully degrades to primary-scalar order when the upstream is unreachable, surfacing the reason underembedding_rerank.reason. - MODIS LST is rate-limited.
modis.lst_day_8daymaterialises through the NASA/ORNL REST API at roughly 30 s per cell. Hunter mode caps the per-region fan-out for the LST family to 8 cells (env overrideEMEM_HUNTER_SLOW_BAND_CAP) so urban-heat queries return inside the gateway timeout. - No interactive notebook UI. For exploration there is
/humans(try-it drawer, manifest grid, ontology SVG); for analytics, drive from a notebook against the REST or MCP endpoint.
Resources
| Agent loop | https://emem.dev/agents.md |
| Wire spec | https://emem.dev/spec.md |
| llms.txt | https://emem.dev/llms.txt |
| OpenAPI 3.1 | https://emem.dev/openapi.json |
| MCP | https://emem.dev/mcp |
| Verify | https://emem.dev/verify |
| Container | ghcr.io/vortx-ai/emem:latest (multi-arch, anonymously pullable) |
| HF Space | huggingface.co/spaces/vortx-ai/emem |
| MCP Directory | docs/mcp-directory.md |
| Issues / PRs | github.com/Vortx-AI/emem/issues |
| Security | SECURITY.md, avijeet@vortx.ai |
License
Apache-2.0. See LICENSE and NOTICE.
Default-build data sources are open: Copernicus DEM, JRC GSW (CC-BY 4.0), Hansen GFC, ESA WorldCover (CC-BY 4.0), Overture Maps (places, buildings, transportation, divisions/division_area; ODbL / CDLA-Permissive), Fields of The World (CC-BY 4.0), GeoNames cities-5000 (CC-BY 4.0), OSM (ODbL), met.no, Open-Meteo, Tessera. No API keys, no operator credentials, no SaaS lock-in.
Recommended MCP Servers
How it compares
Signed place-memory protocol MCP, not a generic SQL or Redis connector.
FAQ
What does emem - Earth memory protocol do?
Content-addressed, ed25519-signed memory of every place on Earth. Apache-2.0, no keys for reads.
When should I use emem - Earth memory protocol?
User asks about emem - Earth memory protocol mcp, content-addressed, ed25519-signed memory of every place on earth. apac.
Is this MCP server safe to install?
Review the Security Audits panel on this page before installing in production.