Embedded C FFI
momo/ffi exposes a small C ABI over the embedded MomoEngine runtime. This is the embedded integration surface added alongside the server codebase. It is separate from the REST API and MCP.
Overview
Section titled “Overview”- Build target:
momo-ffi - Header:
momo/ffi/include/momo.h - Rust implementation:
momo/ffi/src/lib.rs - Example client:
momo/ffi/examples/c/main.c
The FFI returns raw JSON strings from engine methods. It does not use the REST response envelope documented in API Reference.
From momo/:
cargo build -p momo-ffiThis produces:
target/debug/libmomo_ffi.dylibtarget/debug/libmomo_ffi.affi/include/momo.h
The crate is built as both cdylib and staticlib.
Minimal C Example
Section titled “Minimal C Example”Build the library first:
cd momocargo build -p momo-ffiThen build the example:
cd ffi/examples/ccc main.c -I../../include -L../../../target/debug -lmomo_ffi -o momo_ffi_exampleRun it on macOS with the built library on the loader path:
DYLD_FALLBACK_LIBRARY_PATH=../../../target/debug ./momo_ffi_exampleThe example creates an engine, stores one memory, searches memories, then frees all returned pointers correctly.
Engine Lifecycle
Section titled “Engine Lifecycle”Typical call flow:
- Create an engine with
momo_engine_new - Optionally start workers with
momo_engine_start_workers - Call one or more JSON APIs
- Free every returned string with
momo_string_free - Stop workers if you started them
- Free the engine with
momo_engine_free
Exported ABI
Section titled “Exported ABI”typedef struct MomoEngine MomoEngine;
void momo_string_free(char *ptr);
MomoEngine *momo_engine_new(const char *config_json, bool rebuild_embeddings, char **error_out);void momo_engine_free(MomoEngine *engine);
bool momo_engine_start_workers(MomoEngine *engine, char **error_out);void momo_engine_stop_workers(MomoEngine *engine);
char *momo_engine_create_memory_json(MomoEngine *engine, const char *request_json, char **error_out);char *momo_engine_search_memories_json(MomoEngine *engine, const char *request_json, char **error_out);char *momo_engine_search_documents_json(MomoEngine *engine, const char *request_json, char **error_out);Error Handling and Memory Management
Section titled “Error Handling and Memory Management”- On success, JSON functions return a heap-allocated
char *. - On failure, JSON functions return
NULLand write an error string toerror_out. momo_engine_newreturnsNULLon failure.- Free both successful responses and error strings with
momo_string_free. - Passing a null engine pointer to the JSON functions is treated as an error.
Minimal pattern:
char *error = NULL;char *response = momo_engine_search_memories_json(engine, request_json, &error);if (response == NULL) { fprintf(stderr, "%s\n", error); momo_string_free(error); return 1;}
puts(response);momo_string_free(response);Configuration
Section titled “Configuration”momo_engine_new accepts either explicit config JSON or environment-driven config.
Environment-driven configuration
Section titled “Environment-driven configuration”Pass NULL for config_json:
MomoEngine *engine = momo_engine_new(NULL, false, &error);This uses the same Config::from_env() behavior as the server. Relevant variables include:
DATABASE_URLEMBEDDING_MODELEMBEDDING_DIMENSIONSEMBEDDING_BATCH_SIZEEMBEDDING_INGEST_BATCH_SIZEEMBEDDING_DUAL_MODELEMBEDDING_INGEST_BATCH_PAUSE_MSEMBEDDING_API_KEYEMBEDDING_BASE_URLEMBEDDING_TIMEOUTEMBEDDING_MAX_RETRIESEMBEDDING_RATE_LIMITOCR_MODELTRANSCRIPTION_MODELTRANSCRIPTION_MODEL_PATHENABLE_INFERENCES
Explicit config JSON
Section titled “Explicit config JSON”Pass a serialized Rust Config object as JSON if you want the embedding runtime to be configured directly by the host application instead of the process environment.
rebuild_embeddings
Section titled “rebuild_embeddings”The rebuild_embeddings argument controls dimension mismatch handling during startup:
false: reject startup when stored vectors do not match the configured embedding dimensionstrue: rebuild when dimensions do not match
If you choose rebuild mode, worker-backed processing may matter for how quickly queued re-embedding work is completed.
Worker Behavior
Section titled “Worker Behavior”momo_engine_start_workers starts Momo’s background workers for the embedded engine. Use this when your host application needs worker-driven behavior such as background processing or re-embedding flows.
momo_engine_stop_workers shuts them down cleanly.
For simple synchronous memory creation and search calls, you can create an engine and use the JSON APIs without starting workers.
JSON APIs
Section titled “JSON APIs”The FFI JSON contracts are engine-level contracts, not REST DTOs. Naming is mostly snake_case, with a few fields preserved from existing search request models such as rewriteQuery and forgottenMemories.
Create Memory
Section titled “Create Memory”Function:
char *momo_engine_create_memory_json(MomoEngine *engine, const char *request_json, char **error_out);Request:
{ "content": "User prefers dark mode", "container_tag": "ffi-example", "is_static": false, "memory_type": "fact"}Response:
{ "id": "V1StGXR8_Z5jdHi6B-myT", "memory": "User prefers dark mode", "space_id": "default", "container_tag": "ffi-example", "version": 1, "is_latest": true, "parent_memory_id": null, "root_memory_id": null, "memory_relations": {}, "source_count": 0, "is_inference": false, "is_forgotten": false, "is_static": false, "forget_after": null, "forget_reason": null, "memory_type": "fact", "last_accessed": null, "confidence": null, "metadata": {}, "created_at": "2026-03-30T00:00:00Z", "updated_at": "2026-03-30T00:00:00Z"}Notes:
- The request uses
content. - The returned domain object uses
memoryfor the stored text. - The response is a raw serialized
Memory, not{ "data": ... }.
Search Memories
Section titled “Search Memories”Function:
char *momo_engine_search_memories_json(MomoEngine *engine, const char *request_json, char **error_out);Request:
{ "q": "dark mode", "container_tag": "ffi-example", "threshold": 0.7, "limit": 5, "rerank": true, "rewriteQuery": true, "include": { "documents": true, "summaries": true, "related_memories": true, "forgottenMemories": false }}Response shape:
{ "results": [], "total": 0, "timing": 12, "rewritten_query": "dark mode preferences"}Search Documents
Section titled “Search Documents”Function:
char *momo_engine_search_documents_json(MomoEngine *engine, const char *request_json, char **error_out);Request:
{ "q": "dark mode", "container_tags": ["ffi-example"], "limit": 5, "rerank": true, "rewriteQuery": true}Response shape:
{ "results": [], "total": 0, "timing": 8, "rewritten_query": "dark mode preferences"}Important Differences From REST
Section titled “Important Differences From REST”- No HTTP transport
- No Bearer auth layer
- No REST response envelope
- Domain JSON is returned directly
- FFI requests are mostly snake_case
- Some existing request-model fields still use camelCase, such as
rewriteQueryandforgottenMemories
If you need HTTP integration, use the REST endpoints in API Reference instead.
Caveats
Section titled “Caveats”momo/ffiis an embedded-engine API, not a direct vector-generation API.- The included example currently sets
OCR_MODEL=openai/vision; the documented OCR provider name elsewhere in the project isopenai/gpt-4o. - The example also sets
TRANSCRIPTION_MODEL=openai/whisper-1; if you use cloud OCR or transcription providers, configure the matching API keys as well.