Framework-agnostic SDK for building Cadence AI agent plugins
Project description
What is this?
Cadence SDK lets you build AI agent plugins that are completely decoupled from any orchestration framework. You define tools and domain logic; the Cadence platform handles LLM configuration, routing, and multi-agent orchestration.
A plugin is two things:
- A Plugin (stateless factory) — declares metadata and creates agent instances
- An Agent — holds tools, a system prompt, and optional lifecycle hooks
The SDK provides the base classes, decorators, and types to wire these together.
Installation
pip install cadence-sdk
Quick Start
Create my_plugin/plugin.py:
from cadence_sdk import BasePlugin, BaseSpecializedAgent, PluginMetadata, uvtool, plugin_settings, UvTool
from typing import List
class MyAgent(BaseSpecializedAgent):
def initialize(self, config: dict) -> None:
self.api_key = config["api_key"]
self._search_tool = self._make_search_tool()
def _make_search_tool(self) -> UvTool:
@uvtool
def search(query: str) -> str:
"""Search for information."""
return call_api(query, self.api_key)
return search
def get_tools(self) -> List[UvTool]:
return [self._search_tool]
def get_system_prompt(self) -> str:
return "You are a helpful assistant."
@plugin_settings([
{"key": "api_key", "type": "str", "description": "API key", "sensitive": True, "required": True},
{"key": "timeout", "type": "int", "description": "Request timeout in seconds", "default": 30},
])
class MyPlugin(BasePlugin):
@staticmethod
def get_metadata() -> PluginMetadata:
return PluginMetadata(
pid="com.example.my_plugin",
name="My Plugin",
version="1.0.0",
description="Does something useful",
)
@staticmethod
def create_agent() -> MyAgent:
return MyAgent()
Cadence auto-discovers any BasePlugin subclass in a plugin.py file — no manual registration needed.
Package:
zip -r my_plugin.zip my_plugin/ -x "**/__pycache__/*" "**/*.pyc"
How to Use
Agents
Every agent must implement two methods:
| Method | Purpose |
|---|---|
get_tools() |
Return a list of UvTool instances |
get_system_prompt() |
Return the system prompt string |
Optional lifecycle hooks:
| Method | Purpose |
|---|---|
initialize(config) |
Set up state when the agent is created; config comes from @plugin_settings |
cleanup() |
Async teardown — close connections, release resources |
Choose which base class to extend:
BaseSpecializedAgent— tool-focused agent for any multi-agent mode (supervisor, coordinator, handoff)BaseScopedAgent— context-anchored agent for grounded mode; requiresload_anchor(resource_id)andbuild_scope_rules(context)- Both — extend both classes to support grounded and standard modes in one plugin
Plugins
A plugin is a stateless factory. Implement two static methods:
| Method | Purpose |
|---|---|
get_metadata() |
Return a PluginMetadata (pid, name, version, description) |
create_agent() |
Return a fresh agent instance |
Optional static methods: validate_dependencies(), get_settings_schema(), health_check().
Tools
Use @uvtool to wrap any sync or async function as a framework-agnostic tool:
@uvtool
def search(query: str) -> str:
"""Search for information."""
return do_search(query)
@uvtool(stream=True, validate=True)
async def fetch(url: str) -> dict:
"""Fetch URL content."""
return await do_fetch(url)
@uvtool accepts: name, description, args_schema (Pydantic model), stream, stream_filter, validate.
Settings
Use @plugin_settings on your plugin class to declare config shown in the Cadence UI:
@plugin_settings([
{"key": "api_key", "type": "str", "description": "API key", "sensitive": True, "required": True},
{"key": "max_results", "type": "int", "description": "Max results", "default": 10},
])
class MyPlugin(BasePlugin): ...
Each entry requires: key, type ("str" "int" "float" "bool" "list" "dict"), description.
Optional: name (display label), default, required, sensitive.
Settings are passed to agent.initialize(config) as a dict.
Best Practices
- Tools as closures — tools that need agent state should be closures inside a
_make_*factory method so they captureself - Stateless plugins — set
stateless=True(the default) when agents carry no mutable state; this enables instance sharing across orchestrators - Declare dependencies — list pip requirements in
PluginMetadata.dependenciesso the platform auto-installs them on load - Async cleanup — implement
async cleanup()on agents that hold connections or file handles - Configurable system prompt — add
system_promptto@plugin_settingsand returnconfig.get("system_prompt") or defaultfromget_system_prompt() - Validate in CI — use
validate_plugin_structure(MyPlugin)to catch structural issues before deployment
Examples
| Example | Description |
|---|---|
web_search_agent |
Web search via Serper.dev |
recommendation_agent |
Product recommendations via Qdrant |
helpdesk_agent |
Helpdesk support agent |
webpage_reader_agent |
Web page content reader |
Development
git clone https://github.com/jonaskahn/cadence.git
cd cadence/sdk
poetry install --with dev
# Run tests
PYTHONPATH=src python -m pytest tests/ -v
MIT Licensed
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cadence_sdk-2.0.11.tar.gz.
File metadata
- Download URL: cadence_sdk-2.0.11.tar.gz
- Upload date:
- Size: 22.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb91a9a7328d68b2090fde4ca0b4dc96a4ca1e2623b30df3ed1a57ed093dd92a
|
|
| MD5 |
9341d3082e2efd4b6bf351811129d2d9
|
|
| BLAKE2b-256 |
af132d3fd7f8e80782a64592e9fcad72353c5135c797cd17c974cbbc7ad97ab2
|
File details
Details for the file cadence_sdk-2.0.11-py3-none-any.whl.
File metadata
- Download URL: cadence_sdk-2.0.11-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
163a7e97a42964ec5deeafab5e2f612e91c576c367800c5c6317e6c5eaffca37
|
|
| MD5 |
8f450562f49b164d78fd40750883f744
|
|
| BLAKE2b-256 |
6da6f93dfb34f2ebb8b2514fcb04a7ef8c226837a145a59a021ca73c8d2288a6
|