cortex-sdk 1.6.11

SDK for developing Cortex plugins — tools, skills, and extensions
Documentation

Cortex SDK

The official Rust SDK for Cortex trusted native plugins.

cortex-sdk is the public boundary between a plugin crate and the Cortex runtime. It defines plugin metadata, tool traits, runtime invocation context, structured results, media attachments, effect declarations, and the stable C-compatible native ABI used by trusted in-process plugins.

Process-isolated JSON plugins do not need this crate. They are described by a plugin manifest and a child-process command. Use cortex-sdk when you are building a reviewed native plugin that exports cortex_plugin_init and is loaded into the daemon process.

Install

[dependencies]
cortex-sdk = "1.6.11"
serde_json = "1"

Native plugins are built as cdylib shared libraries:

[lib]
crate-type = ["cdylib", "rlib"]

Minimal Plugin

use cortex_sdk::prelude::*;

#[derive(Default)]
struct DevPlugin;

impl MultiToolPlugin for DevPlugin {
    fn plugin_info(&self) -> PluginInfo {
        PluginInfo {
            name: "example".into(),
            version: env!("CARGO_PKG_VERSION").into(),
            description: "Example Cortex native plugin".into(),
        }
    }

    fn create_tools(&self) -> Vec<Box<dyn Tool>> {
        vec![Box::new(WordCount)]
    }
}

struct WordCount;

impl Tool for WordCount {
    fn name(&self) -> &'static str {
        "word_count"
    }

    fn description(&self) -> &'static str {
        "Count words in provided text."
    }

    fn input_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "text": { "type": "string" }
            },
            "required": ["text"]
        })
    }

    fn execute(&self, input: serde_json::Value) -> Result<ToolResult, ToolError> {
        let text = input["text"]
            .as_str()
            .ok_or_else(|| ToolError::InvalidInput("missing text".into()))?;
        Ok(ToolResult::success(format!("{} words", text.split_whitespace().count())))
    }
}

cortex_sdk::export_plugin!(DevPlugin);

Runtime Context

Tools that need session metadata, actor identity, transport/source, execution scope, progress updates, or observer text should override Tool::execute_with_runtime:

fn execute_with_runtime(
    &self,
    input: serde_json::Value,
    ctx: InvocationContext,
    runtime: &dyn ToolRuntime,
) -> Result<ToolResult, ToolError> {
    runtime.progress("working");
    runtime.observer_text("tool", &format!("session={}", ctx.session_id));
    self.execute(input)
}

Use runtime callbacks for operator-visible progress only. Tool return values remain the authoritative data passed back to the model.

Effects and Policy

Declare side effects so Cortex can apply policy and permission gates before a tool runs:

fn effects(&self, input: &serde_json::Value) -> Vec<ToolEffect> {
    vec![ToolEffect::file_read(input["path"].as_str().unwrap_or_default())]
}

Good effect declarations should be specific enough for the operator to understand the blast radius: path, network host, process command, or stateful operation. Do not hide side effects in generic descriptions.

Media Results

Return files through structured attachments instead of calling transport APIs:

Ok(ToolResult::success("generated image").with_media(Attachment {
    media_type: "image".into(),
    mime_type: "image/png".into(),
    url: "/tmp/output.png".into(),
    caption: Some("Generated image".into()),
    size: None,
}))

Cortex is responsible for delivering attachments through the active transport.

Native ABI

The runtime loads a native plugin with dlopen, calls cortex_plugin_init, and receives a CortexPluginApi function table. Rust trait objects never cross the dynamic-library boundary. Structured values move through UTF-8 JSON buffers allocated by the plugin and released through the SDK ABI helpers.

NATIVE_ABI_VERSION is the ABI compatibility marker. Plugin manifests must set [native].abi_version to the ABI version they target.

Manifest

Native plugins also need a Cortex manifest:

name = "example"
version = "0.1.0"
description = "Example Cortex native plugin"
cortex_version = "1.6.11"
trust = "trusted_native"

[capabilities]
provides = ["tools"]
file_read = []
file_write = []
network = []
process = false
secrets = false
background = false

[sandbox]
level = "trusted_in_process"

[native]
library = "lib/libexample.so"
isolation = "trusted_in_process"
abi_version = 1

Release Checklist

  1. Build the shared library with cargo build --release.
  2. Copy the library into the manifest-declared lib/ path.
  3. Run cortex plugin review ..
  4. Run cortex plugin test ..
  5. Sign with a private key stored outside the repository.
  6. Pack with cortex plugin pack ..
  7. Publish the .cpx archive and checksum as release assets.

Documentation

License

MIT.