Concepts
The mental model behind the SDK in 800 words — Protocols, native vs plugin tools, hash contract, security tiers.
Last updated: 2026年5月19日
The mental model behind the SDK in 800 words.
Protocols, not base classes
The SDK defines Plugin, Agent, Tool, Route, Config, KV, Leash
as typing.Protocol subclasses with the @runtime_checkable decorator.
You implement these contracts structurally — by having the right
attributes and methods — instead of inheriting from an ABC.
from dryade_plugins_sdk import Plugin
class MyPlugin: # NO base class
name = "my_plugin"
version = "0.1.0"
description = "..."
core_version_constraint = ">=1.0.0,<2.0.0"
def register(self, registry): ...
assert isinstance(MyPlugin(), Plugin) # True — structural match
This means:
- Your IDE catches missing methods at edit time — without you needing to import the SDK at every layer.
- The host can verify conformance at load time with a single
isinstance(plugin, Plugin)call. - You never inherit Dryade’s implementation details — protocols are a one-way contract.
Manifest v2
Every plugin ships a dryade.json at its root. v2 (the only supported
version) has a strict JSON schema with these required fields:
| Field | Type | Notes |
|---|---|---|
manifest_version | "2.0" | locked |
name | string, snake_case | matches the directory name |
version | semver | strict 2.0.0 |
description | string | shown in marketplace cards |
required_tier | starter / team / enterprise | never community |
author | string | your name or org |
core_version_constraint | PEP 440 spec | e.g. >=1.0.0,<2.0.0 |
Optional fields cover UI bundles, sandbox policy, MCP servers, agent metadata, and more — see API Reference for the full surface.
Tiers
starter— single-author plugins, max 1 user, no custom plugin slots.team— up to N users from the same org (max_usersin the signed allowlist).enterprise— full multi-org slot allocation.
Tier limits are enforced by the Dryade host based on the signed
allowlist, not by the SDK or CLI. The CLI rejects --tier community at
scaffold + validate + package time because the platform itself
has no community tier.
Signing
Authors generate an Ed25519 keypair via dryade plugin keygen. The CLI
embeds the public key in the .dryadepkg and signs the manifest’s hash
with the private key. Private keys live at ~/.dryade-author/dev-key.priv
with mode 0o600 — the CLI refuses to load weaker permissions.
When you submit to the marketplace, the marketplace re-signs with its own dual Ed25519 + ML-DSA-65 keys before publishing in the signed allowlist. Authors never see the production signing material.
Hashing — contract version 4
Every plugin source file gets hashed with both SHA-256 and SHA3-256.
The pair is computed by walking the plugin tree, collecting every .py
file, and chaining path:content segments through both hash families. The
final 64-char hex digests land in plugin_hash_sha256 and
plugin_hash_sha3_256 fields of the packaged manifest.
The host re-computes both digests at load time and refuses to load if
either drifts. The compute_plugin_hash_pair function in
dryade_plugins_sdk.packaging is the canonical implementation;
tests/test_hash_conformance.py independently reimplements it in stdlib
to catch drift.
The current contract version is 4. SDK consumers should pin
dryade-plugins-sdk>=1.0.0,<2.0.0 to stay on contract 4 — a future major
SDK bump signals a hash-algorithm change.
Sandbox / Leash
Plugins can advertise an isolation policy via a Leash attribute on the
plugin class or instance:
from dryade_plugins_sdk import IsolationLevel
class MyLeash:
isolation: IsolationLevel = IsolationLevel.PROCESS
cpu_quota: float | None = 0.5
memory_mb: int | None = 512
network: bool = True
class MyPlugin:
leash = MyLeash()
...
The host honors the Leash if it can (live levels: NONE, PROCESS,
LANGUAGE). Levels declared as future support (CONTAINER, GVISOR)
fail-closed at the host until the sandbox lands — see
examples/with_llm/
for the canonical request shape.
Contract version
The constant dryade_plugins_sdk.CONTRACT_VERSION (also accessible as
__contract_version__) is 4 at this SDK release. Plugins built against
SDK 1.x will continue to load on hosts that advertise contract 4. A future
SDK 2.0 will signal a contract bump (e.g. switch hash family, add a
required field) and host loaders will refuse plugins from the older
contract.
You usually do not need to read this value at runtime — the dryade CLI
embeds it in the packaged manifest’s contract_version field, and the
host validates at load.