Skip to content

YAMS Plugin System

YAMS loads plugins to extend extraction, embeddings, storage, search, and graph backends.

Type Use case Language Deployment
External Prototyping, integration, scripting Python, JS, any Subprocess (JSON-RPC over stdio)
Native Performance-critical, in-process C/C++ Shared library (C ABI)

Trust and discovery

Default deny. Only paths in the trust file load.

yams plugin trust add ~/.local/lib/yams/plugins   # trust a directory
yams plugin trust list
yams plugin trust remove <path>

yams plugin scan                                  # discover
yams plugin list                                  # loaded
yams plugin load <path|name>
yams plugin unload <name>
yams plugin info <name>
yams plugin health
yams doctor plugin <name>                         # diagnose one

Trust file: <data_dir>/plugins.trust (default ~/.local/share/yams/plugins.trust). Legacy ~/.config/yams/plugins_trust.txt is imported.

Search order:

  1. Persisted trusted roots from plugins.trust
  2. [daemon].plugin_dir and [daemon|plugins].trusted_paths in config
  3. Built-in defaults: ~/.local/lib/yams/plugins, /opt/homebrew/lib/yams/plugins (macOS), /usr/local/lib/yams/plugins, /usr/lib/yams/plugins — unless strict mode is on

Strict mode: [daemon].plugin_dir_strict = true or YAMS_PLUGIN_DIR_STRICT=1. Dev override: YAMS_PLUGIN_TRUST_ALL=1.

Bundled plugins

Plugin Purpose Details
onnx ONNX Runtime embeddings (CPU + GPU) plugins/onnx/README.md
object_storage_s3 S3 / R2-compatible object storage backend plugins/object_storage_s3/README.md
zyp PDF text + metadata extraction plugins/zyp/
symbol_extractor_treesitter Tree-sitter symbols for 18 languages plugins/symbol_extractor_treesitter/
glint GLiNER natural-language entity extraction plugins/glint/README.md
hound Graph adapter mapping Hound → YAMS KG plugins/hound/
yams-ghidra-plugin Ghidra binary analysis (external, PyGhidra) plugins/yams-ghidra-plugin/

Standard interfaces

Interface Header Purpose
content_extractor_v1 include/yams/plugins/content_extractor_v1.h Document text extraction
symbol_extractor_v1 include/yams/plugins/symbol_extractor_v1.h Source / binary symbols
entity_extractor_v2 include/yams/plugins/entity_extractor_v2.h Named entity extraction
search_provider_v1 include/yams/plugins/search_provider_v1.h Search backend
graph_adapter_v1 See docs/api/graph_adapter_v1.md KG adapter
model_provider_v1 include/yams/ml/ Embedding model provider
object_storage_v1 See docs/api/storage_plugin_v1.md Object storage

Interface versions are tracked in docs/spec/interface_versions.json.


External plugins (JSON-RPC)

External plugins run as subprocesses communicating JSON-RPC 2.0 over stdio. Every external plugin must implement:

Method Purpose Response
handshake.manifest Plugin metadata {name, version, interfaces, capabilities}
plugin.init Initialize with config {status: "ok"}
plugin.health Health status {status: "ok"\|"degraded"\|"error"}
plugin.shutdown Graceful cleanup {status: "ok"}

Per-interface methods are defined in docs/spec/external_plugin_jsonrpc_protocol.md.

Minimal Python example

#!/usr/bin/env python3
import json, sys

def handle(req):
    m = req.get("method", "")
    if m == "handshake.manifest":
        return {"name": "my_plugin", "version": "1.0.0", "interfaces": []}
    if m in ("plugin.init", "plugin.health", "plugin.shutdown"):
        return {"status": "ok"}
    raise ValueError(f"Unknown method: {m}")

for line in sys.stdin:
    req = json.loads(line)
    try:
        resp = {"jsonrpc": "2.0", "id": req.get("id"), "result": handle(req)}
    except Exception as e:
        resp = {"jsonrpc": "2.0", "id": req.get("id"),
                "error": {"code": -32603, "message": str(e)}}
    print(json.dumps(resp), flush=True)

The higher-level yams_sdk.BasePlugin is in external/yams-sdk/.

Plugin directory layout

my_plugin/
├── yams-plugin.json    # manifest (required)
├── plugin              # compiled binary (Linux/macOS)
├── plugin.exe          # compiled binary (Windows)
└── plugin.py           # interpreter fallback

Manifest fields and ${plugin_dir} substitution: see docs/spec/plugin_spec.md.

Process lifecycle

Unstarted → Starting → Ready ⇄ Busy → ShuttingDown → Terminated
                ↓                         ↓
             Failed ←───────────────────── ┘

Crashed plugins are restarted with exponential backoff (up to 3 retries). Unix uses SIGTERM → SIGKILL with process groups; Windows uses Job Objects and TerminateProcess.


Native plugins (C ABI)

Required entry points — full signatures in include/yams/plugins/abi.h:

int         yams_plugin_get_abi_version(void);
const char* yams_plugin_get_name(void);
const char* yams_plugin_get_version(void);
const char* yams_plugin_get_manifest_json(void);
int         yams_plugin_get_interface(const char* iface_id, uint32_t version, void** out);
int         yams_plugin_init(const char* config_json, const void* host_context);
void        yams_plugin_shutdown(void);
int         yams_plugin_get_health_json(char** out_json);  // optional

Interfaces are exposed as vtables (see include/yams/plugins/*.h). Memory: plugin allocates with malloc, host frees with free. Vtables have static lifetime. Thread-safe unless documented otherwise.

Object storage provider compatibility

  • Cloudflare R2 — tested in-repo.
  • AWS S3 — same interface, not validated by automated tests here.

See plugins/object_storage_s3/README.md for setup and docs/api/storage_plugin_v1.md for capability expectations.

References

Resource Path
C ABI spec docs/spec/plugin_spec.md
JSON-RPC spec docs/spec/external_plugin_jsonrpc_protocol.md
Interface versions docs/spec/interface_versions.json
Interface headers include/yams/plugins/*.h
Python SDK external/yams-sdk/
Mock plugin tests/fixtures/mock_plugin.py