YAMS Plugin ABI Specification¶
Core C-ABI Plugin Interface¶
The YAMS plugin system is built around a stable C ABI that enables plugins to expose services to the host and optionally call back into host services.
Plugin Entry Points¶
Every plugin MUST implement the following symbols:
// Return the plugin ABI version (always 1)
int yams_plugin_get_abi_version(void);
// Return the plugin name (static string, lifetime of plugin)
const char* yams_plugin_get_name(void);
// Return the plugin version (static string, lifetime of plugin)
const char* yams_plugin_get_version(void);
// Return the plugin manifest as JSON (static string, lifetime of plugin)
const char* yams_plugin_get_manifest_json(void);
// Get an interface vtable by ID and version
// Returns 0 on success, non-zero on error/interface not found
int yams_plugin_get_interface(const char* iface_id, uint32_t version, void** out_iface);
// Initialize the plugin with config JSON and optional host context
// Returns 0 on success, non-zero error code on failure
int yams_plugin_init(const char* config_json, const void* host_context);
// Shutdown the plugin (cleanup resources)
void yams_plugin_shutdown(void);
// Optional: Get health status as JSON (allocated with malloc, host frees)
// Returns 0 on success, non-zero if not implemented
int yams_plugin_get_health_json(char** out_json);
Memory Management¶
- Plugin-allocated memory: For any function that returns allocated memory (like
get_health_json), the plugin MUST usemalloc()/calloc(). The host is responsible for callingfree(). - Host-allocated memory: When the host provides data to plugins via callbacks, the host allocates and frees the memory.
- Interface vtables: Interface pointers returned by
get_interfacehave static lifetime for the duration of the plugin load.
Error Codes¶
Plugins SHOULD use standard error codes:
#define YAMS_PLUGIN_OK 0
#define YAMS_PLUGIN_ERR_INVALID 1
#define YAMS_PLUGIN_ERR_INCOMPATIBLE 2
#define YAMS_PLUGIN_ERR_NOT_FOUND 3
#define YAMS_PLUGIN_ERR_IO 4
#define YAMS_PLUGIN_ERR_INTERNAL 5
#define YAMS_PLUGIN_ERR_UNSUPPORTED 6
Interface VTables¶
Standard Interface Pattern¶
All interfaces follow this pattern:
typedef struct iface_name_v1 {
void* handle; // Plugin-specific context
// Interface methods...
} iface_name_v1_t;
Required Interfaces¶
model_provider_v1¶
Header: include/yams/plugins/model_provider_v1.h
typedef struct model_provider_v1 {
void* handle;
// Set progress callback for long operations (optional)
int (*set_progress_callback)(void* handle,
void (*callback)(void* user_data, const char* phase, int progress, int total),
void* user_data);
// Load a model (non-blocking)
int (*load_model)(void* handle, const char* model_id, const char* model_path, const char* options_json);
// Unload a model
int (*unload_model)(void* handle, const char* model_id);
// Check if model is loaded
int (*is_model_loaded)(void* handle, const char* model_id, bool* out_loaded);
// Get list of loaded models (plugin allocates arrays, host frees)
int (*get_loaded_models)(void* handle, char*** out_ids, uint32_t* out_count);
void (*free_model_list)(void* handle, char** ids, uint32_t count);
// Generate single embedding
int (*generate_embedding)(void* handle, const char* model_id,
const uint8_t* input, size_t input_len,
float** out_vec, uint32_t* out_dim);
void (*free_embedding)(void* handle, float* vec, uint32_t dim);
// Generate batch embeddings
int (*generate_embedding_batch)(void* handle, const char* model_id,
const uint8_t** inputs, const size_t* lens, uint32_t batch,
float*** out_vecs, uint32_t* out_batch, uint32_t* out_dim);
void (*free_embedding_batch)(void* handle, float** vecs, uint32_t batch, uint32_t dim);
// v1.2 extensions (optional, may return UNSUPPORTED)
int (*get_embedding_dim)(void* handle, const char* model_id, uint32_t* out_dim);
int (*get_runtime_info_json)(void* handle, const char* model_id, char** out_json);
void (*free_string)(void* handle, char* str);
int (*set_threading)(void* handle, const char* model_id, uint32_t intra_threads, uint32_t inter_threads);
} model_provider_v1_t;
content_extractor_v1¶
Header: include/yams/plugins/content_extractor_v1.h
typedef struct content_extractor_v1 {
void* handle;
// Extract content from a document
int (*extract_content)(void* handle, const char* file_path,
char** out_text, char** out_metadata_json);
void (*free_extracted_content)(void* handle, char* text, char* metadata);
// Get supported file extensions (plugin allocates, host frees)
int (*get_supported_extensions)(void* handle, char*** out_extensions, uint32_t* out_count);
void (*free_extension_list)(void* handle, char** extensions, uint32_t count);
} content_extractor_v1_t;
Host Services API (Optional)¶
Plugins that need to call back into YAMS can use the Host Services API.
Host Context¶
During yams_plugin_init, the host MAY pass a yams_plugin_host_context_v1 struct:
typedef struct yams_plugin_host_context_v1 {
uint32_t version; // YAMS_PLUGIN_HOST_SERVICES_API_VERSION
const document_service_v1* document_service;
const search_service_v1* search_service;
// Additional services may be added in future versions
} yams_plugin_host_context_v1_t;
Document Service v1¶
typedef struct document_service_v1 {
void* handle;
int (*list_documents)(void* handle, const list_documents_request_t* req,
list_documents_response_t** out_res);
void (*free_list_documents_response)(void* handle, list_documents_response_t* res);
int (*get_document)(void* handle, const get_document_request_t* req,
get_document_response_t** out_res);
void (*free_get_document_response)(void* handle, get_document_response_t* res);
// Additional methods...
} document_service_v1_t;
Plugin Manifest¶
Each plugin MUST provide a JSON manifest via yams_plugin_get_manifest_json():
{
"name": "plugin_name",
"version": "1.0.0",
"description": "Brief description",
"interfaces": [
{
"id": "model_provider_v1",
"version": 2
}
],
"abi_version": 1,
"capabilities": [],
"dependencies": []
}
Lifecycle¶
- Discovery: Host scans for plugin files and reads symbols without side effects
- Validation: Host verifies ABI version, manifest format, and required interfaces
- Initialization: Host calls
yams_plugin_init()with config and optional host context - Interface Registration: Host retrieves interface vtables via
yams_plugin_get_interface() - Operation: Host calls into plugin interfaces as needed
- Shutdown: Host calls
yams_plugin_shutdown()before unloading
Security Considerations¶
- Plugins run in the same process space as the host
- Host should validate plugin signatures and maintain a trust list
- Plugins should validate all input parameters and handle errors gracefully
- Memory safety is critical - use proper bounds checking and null checks
Threading¶
- Plugin initialization and shutdown are single-threaded
- Interface methods MAY be called from multiple threads concurrently
- Plugins MUST implement their own synchronization if needed
- Callbacks MAY be invoked from background threads
Versioning¶
- Plugin ABI version is incremented for breaking changes
- Interface versions are incremented independently
- Host should support multiple interface versions in parallel
- Plugins should advertise the highest interface version they support
Best Practices¶
- Use static allocation for fixed-size data structures
- Validate all pointers before dereferencing
- Provide meaningful error messages
- Implement graceful degradation for optional features
- Use consistent naming conventions across interfaces
- Document thread safety guarantees for each method