Skip to main content
cognee-rust ships four language bindings on top of the Rust core. All share the same SDK-tier implementation via cognee-bindings-common (portable op bodies + stable error codes), so their surfaces line up 1:1. Each exposes the same flow: warm() → add() → cognify() → search(). Module-level helpers exist in each binding for logging/telemetry setup. The serve() / disconnect() cloud helpers are not part of the OSS bindings. The full per-language method list lives in each binding’s README and its generated docs.

Custom pipelines

Alongside the Cognee SDK surface, the Python, C and JS bindings expose the low-level pipeline API (Pipeline, tasks, a watcher, run handles) for composing your own tasks. The JS and C specifics are below. In JS, every task callback receives (input, ctx) and may return its result directly or through a Promise; a throw or a rejection fails the task with the error’s message. Each creator also has an async-named alias matching the C API (cg_task_async, cg_task_async_stream, …): Stream (“iter”) callbacks may return an array, any iterable (such as a generator) or an async iterable (such as an async function*). Iterables are pulled lazily, one item per downstream request. A batch task must directly follow a stream task, which accumulates its batch.
A stream that fails after it has started yielding fails the run. That failure is not retried, and items already passed downstream are not rolled back (see Tasks). In C, cg_pipeline_execute_in_background and cg_pipeline_execute_async keep their own reference to the watcher, so cg_pipeline_watcher_destroy() may be called right after starting the run. In those two modes, watcher callbacks run on runtime worker threads and can run concurrently. Watcher state must be thread-safe, and callbacks must not block or call blocking cg_* entry points. While a run is in flight, cg_pipeline_set_* and cg_pipeline_add_task on that pipeline are refused rather than aborting the process: they become no-ops and set cg_last_error_message(). The error is sticky, so call cg_last_error_clear() first to detect a refusal. The pipeline is mutable again once the run is done. See capi/include/cognee.h.

Process-wide configuration (logging, OTLP, analytics)

Logging, OpenTelemetry export and product analytics each configure a process-wide singleton, so they are not handle settings: a handle’s config.set(...) does not reach them. Each binding exposes the same module-level surface, resolved by one shared path (cognee_bindings_common::process_config): defaults < environment < options passed from code. See Configuration: Logging and Observability & telemetry for the keys. Analytics are on by default (opt-out). The switch wins over TELEMETRY_DISABLED / ENV, which are read when an event is sent (so a .env loaded later counts). Logging and OTLP setup latch on their first call. The argument-less forms (setup_logging(), cognee_setup_logging(), …) are unchanged and read the environment only.

Configuration

All four delegate to the same ConfigManager in cognee-bindings-common; the difference is purely ergonomic (design decision A3.1, intentional for 0.1.0): The generic set reaches every settable key: the Settings keys in the key registry and the keys of the component config sections compiled into the build, by canonical name (llm.model) or Python flat alias (llm_model). So C and Python deliberately ship only the generic + bulk setters; JS adds the granular setters as thin (infallible) sugar over the same underlying settings. Type errors surface with the stable CONFIG_TYPE_MISMATCH code (C: CG_ERR_CONFIG_TYPE_MISMATCH) at the call site. Field names are camelCase in JS and snake_case in Python/C/Java.

Unification path (post-0.1.0)

If full parity is required, mirror the JS macro-driven approach: add set_llm_model(value) / cg_sdk_config_set_llm_model(handle, value) etc. as thin set_str("llm_model", value) wrappers in each binding’s idiomatic case (~0.5 d/binding, mechanical).