openapi: 3.2.0 info: description: emem is shared memory for AI agents working together in the real world. license: name: Apache-2.0 title: emem Derive API version: 2.4.0 x-emem-surface-asymmetry: memory_notes: MCP only reach_them_at: POST /mcp, method tools/call read_side_is_here: - /v1/memory/search - /v1/memory/sse - /memories/{path} tools: - emem_memory_create - emem_memory_view - emem_memory_delete - emem_memory_rename - emem_memory_str_replace - emem_memory_supersede why_not_here: These write the agent correspondence plane, which is prose and untrusted-by-declaration. It is deliberately not part of the REST fact surface, and the two planes are kept apart rather than merged for convenience. servers: - description: Hosted instance (HTTPS-only) url: https://emem.dev tags: - name: derive paths: /v1/derive: post: description: 'Register a value YOU computed from facts this responder holds, and get back a citeable `emem:fact:` token whose lineage terminates in emem-signed measurements. The registered fact names its parents by CID, so a stranger walks the DAG down to signed sensor data instead of trusting your summary. Requires an ed25519 `attester` block. What the responder signs is narrow and it says so on the response: that YOU submitted this derivation, over these parents, at this time, and it stored it. NOT that the value is true. Memory algebra: the `derive` operation (https://emem.dev/docs/model.html). When to use: Call when you have computed something from emem facts (a delta, a zone classification, a per-plot verdict, a model output) and need to hand another agent a token for it rather than a claim. Every input token must already resolve here; recall or backfill the parents first. Provenance class is model_output or human_curated; the sensor classes are refused, since this responder did not compute your value. Note the tenancy rule: a derived fact carries no canonical (cell, band, tslot) key, so it will NOT appear in anyone''s emem_recall at that cell. That is the point: you are getting citation and resolution, not an injection into the shared commons. Read it back with emem_memory_token_resolve, or list your own with emem_derive_list. Idempotent per (your key, derivation body): re-registering an identical derivation returns the same token rather than a twin, so retrying a timed-out call is safe.' operationId: emem_derive requestBody: content: application/json: schema: properties: attester: properties: pubkey_b32: type: string sig_b32: type: string required: - pubkey_b32 - sig_b32 type: object band: type: string budget_ms: description: optional soft budget in ms; if registration does not finish in time it returns 202 {status:pending} and completes in the background, and since derive is idempotent a re-POST of the identical body returns the token once it persists (a build under load never exits half-registered). Omit for synchronous 200-or-error. type: integer cell: type: string code_cid: description: optional blake3 of the code that computed the value; recorded, never fetched or run type: string confidence: maximum: 1 minimum: 0 type: number fn_key: description: your recipe key, e.g. same_doy_ndvi_delta@1; not an entry in this responder's registry and never executed by it type: string inputs: description: parent tokens emem:fact::; order is significant and signed items: type: string minItems: 1 type: array op: description: delta | mean | trend | rate | anomaly type: string provenance_class: enum: - model_output - human_curated - estimator type: string tslot_window: description: inclusive [start, end] items: type: integer maxItems: 2 minItems: 2 type: array value: description: any JSON value required: - fn_key - inputs - cell - band - tslot_window - op - value - confidence - provenance_class type: object required: true responses: '200': content: application/json: schema: type: object description: ok '202': description: registration in progress; re-POST the identical body to collect the token '400': content: application/json: schema: properties: details: type: object error: type: string type: object description: invalid argument; `details.code` names which rule refused '401': content: application/json: schema: properties: details: type: object error: type: string type: object description: the caller's ed25519 attester binding is missing or does not verify; `details.how_to_sign` carries the exact digest to sign for this request '404': content: application/json: schema: properties: error: type: string type: object description: not found '409': content: application/json: schema: properties: error: type: string type: object description: conflict (the request contradicts a signed fact, e.g. a token whose cell does not match the fact's own cell) default: content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' description: 'error, the emem.error.v1 envelope. Branch on the stable `code` (see GET /v1/errors), not the message. A malformed or missing-field request body returns `code: invalid_argument` with the offending field named in `message`.' summary: Register a derivation YOU computed over facts this responder holds, and get… tags: - derive /v1/derived: post: description: 'List the derivations registered by one ed25519 key, optionally filtered to a cell (and then a band). The explicit opt-in read for caller-registered derivatives: they hold no canonical key, so no default read path returns them, and this is the only way to enumerate one rather than resolve it by token. When to use: Call to enumerate your own derivations (pass your pubkey_b32), or to inspect what a specific attester has claimed when you already have a reason to trust or audit that key. There is no all-attesters form: naming whose claims you want is the contract, not a filter you can omit.' operationId: emem_derive_list requestBody: content: application/json: schema: properties: attester_pubkey_b32: description: 52-char base32-nopad-lowercase ed25519 pubkey type: string band: description: only narrows when `cell` is also set type: string cell: type: string limit: default: 100 maximum: 1000 minimum: 1 type: integer required: - attester_pubkey_b32 type: object required: true responses: '200': content: application/json: schema: type: object description: ok '400': content: application/json: schema: properties: details: type: object error: type: string type: object description: invalid argument; `details.code` names which rule refused '503': content: application/json: schema: type: object description: ok default: content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' description: 'error, the emem.error.v1 envelope. Branch on the stable `code` (see GET /v1/errors), not the message. A malformed or missing-field request body returns `code: invalid_argument` with the offending field named in `message`.' summary: List the derivations registered by ONE attester, optionally narrowed to a cell… tags: - derive components: schemas: ErrorEnvelope: description: The `emem.error.v1` failure envelope returned by every endpoint on a 4xx/5xx. Branch on the stable `code` (not the human `message`). See GET /v1/errors for the full code catalog. properties: code: description: Stable machine-readable error code. One of the codes in GET /v1/errors. example: invalid_argument type: string details: description: Optional structured recovery hints; present on errors that ship machine-readable next-steps. type: object message: description: Human-readable detail. For invalid_argument this names the offending field (e.g. "missing field `q`"). type: string path: description: Request path that produced the error. example: /v1/ask type: string schema: const: emem.error.v1 type: string required: - code - message - schema type: object