molecule-ai-sdk (0.5.2)
Installation
pip install --index-url https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/ --extra-index-url https://pypi.org/simple molecule-ai-sdkAbout this package
Molecule AI SDK — build plugins (molecule_plugin) AND remote agents that join a Molecule AI org from another machine (molecule_external_workspace).
molecule-ai-sdk
The Molecule AI SDK and contract SSOT. One repo, three things:
-
Two Python packages (published together under the distribution name
molecule-ai-sdkin Molecule's private Gitea package registry — not on public PyPI):molecule_external_workspace— write an agent that runs outside the platform's Docker network and joins a Molecule AI org from another machine. It registers with the platform, pulls secrets, sends heartbeats, discovers peers (A2A), delegates, and detects pause/delete. Public API:RemoteAgentClient,A2AServer.molecule_plugin— build installable plugin directories (rules, skills in agentskills.io format, per-runtime install adaptors) + validators and apython -m molecule_pluginCLI. (See Plugin authoring.)
-
contracts/— the platform contract SSOT. The JSON-Schema (draft 2020-12) IDL for every cross-boundary contract in the platform, plus the cloud-provider YAML SSOT. This is the formermolecule-contractsrepo, folded in and archived here 2026-07-01. See Contracts. -
gen/— generated bindings. Go / TypeScript / Python types + constants emitted fromcontracts/bytools/gen-*.mjs. Consumed bymolecule-coreandmolecule-controlplane(Go, viago.moleculesai.app/sdk/gen/go/...), the storefront (TS), and the runtime (Python). Never hand-edited — a fresh regen must match what's committed (enforced by CI).
molecule-ai-sdk/
├── molecule_external_workspace/ # remote-agent client (RemoteAgentClient / A2AServer)
├── molecule_plugin/ # plugin-authoring SDK + validators + CLI
├── contracts/ # JSON-Schema IDL SSOT + cloudproviders.yaml
│ ├── mcp/ plugin-manifest/ workspace-template/ org-template/
│ ├── catalog/ # catalog-entry + marketplace-service (catalog/publish/install/entitlement)
│ ├── provision-request/ promote-request/ workspace-comms/
│ └── cloudproviders.yaml + cloudproviders.schema.json
├── gen/{go,ts,python}/ # generated bindings (DO NOT EDIT)
├── tools/gen-runtimes.mjs + gen-{go,ts,python}.mjs # Node generators
├── template/ # starter plugin scaffold
└── tests/
Install
SDK_DOWNLOAD="$(mktemp -d)"
python -m pip download --no-deps --dest "$SDK_DOWNLOAD" \
--index-url "https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple" \
molecule-ai-sdk
python -m pip install --index-url https://pypi.org/simple \
"$SDK_DOWNLOAD"/molecule_ai_sdk-*.whl
The Gitea registry does not proxy public PyPI. Download only the private SDK
wheel from Gitea, then install that local wheel while resolving its declared
public dependencies from PyPI. Keeping retrieval in separate commands avoids
both a broken sole-index install, dependency drift, and cross-index dependency
confusion. Authenticate via ~/.netrc (or pip's keyring) — do not inline
credentials in the URL.
Go consumers import the generated bindings via the vanity path (no PyPI needed):
import molcontracts "go.moleculesai.app/sdk/gen/go/molcontracts"
Contracts — the SSOT
Every contract is a pair under its contracts/<domain>/ directory:
*.schema.json— the rules (JSON-Schema draft 2020-12): fields, types,required,enum,constpins,patterns. The enforceable definition.*.contract.json— one canonical instance that MUST validate against its sibling schema. It's the worked example, the CI anchor, and — for value-bearing contracts likemcp-plugin-delivery— the SSOT for the concrete values baked intogen/.
Direction: *.contract.json ──validate──▶ *.schema.json, and
contracts/ ──codegen (tools/gen-*.mjs)──▶ gen/{go,ts,python}. Each domain
directory under contracts/ carries its own README.md
describing that surface.
Eight jobs back this under the strict all-required aggregator in
.gitea/workflows/contracts-codegen-drift.yml: schema validation, codegen drift,
cloud-provider and adapter/prompt/platform conformance, Go parity, and published
binding parity. Regenerate locally after any contract edit and commit the result:
node tools/gen-runtimes.mjs
node tools/gen-go.mjs && node tools/gen-ts.mjs && node tools/gen-python.mjs
Remote agents — molecule_external_workspace
from molecule_external_workspace import RemoteAgentClient
client = RemoteAgentClient(
platform_url="https://<org>.moleculesai.app",
workspace_id="my-agent",
# the auth token is minted on first register() and persisted client-side
)
The client wraps the workspace↔platform HTTP contract (register, pull secrets,
heartbeat, state-poll, A2A peer discovery, delegation, plugin install) — the same
surface captured in contracts/workspace-comms/. A2AServer is the receive side
for agent-to-agent messages.
Plugin authoring — molecule_plugin
A Molecule AI plugin is a directory that bundles rules, skills, and per-runtime install adaptors. Any plugin that conforms to the contract is installable on any Molecule AI workspace whose runtime the plugin supports.
Quick start
Create a validated scaffold directly from the installed wheel:
python -m molecule_plugin init my-plugin --kind skill
cd my-plugin
python -m molecule_plugin validate plugin .
Use --kind mcp for a dependency-free stdio MCP starter or --kind channel
for a supervised channel-daemon starter with a vendored, provider-neutral
channel API v1 client. Names must be lowercase alphanumeric slugs with single
hyphens. The initializer refuses path traversal and never overwrites an
existing directory.
my-plugin/
├── plugin.yaml # name, version, runtimes, description
├── rules/my-rule.md # optional — appended to CLAUDE.md at install
├── skills/my-skill/
│ ├── SKILL.md # instructions injected into the system prompt
│ └── tools/do_thing.py # optional LangChain @tool functions
└── adapters/
├── claude_code.py # one-liner: `from molecule_plugin import AgentskillsAdaptor as Adaptor`
└── codex.py # same
Validate:
from molecule_plugin import validate_manifest
errors = validate_manifest("my-plugin/plugin.yaml")
assert not errors, errors
CLI
python -m molecule_plugin init my-skill-plugin --kind skill
python -m molecule_plugin init my-mcp-plugin --kind mcp
python -m molecule_plugin init my-channel --kind channel
python -m molecule_plugin validate plugin my-plugin/
python -m molecule_plugin validate workspace workspace-configs-templates/claude-code-default/
python -m molecule_plugin validate org org-templates/molecule-dev/
python -m molecule_plugin validate my-plugin/ # kind defaults to 'plugin'
Exit code is 0 when valid, 1 when any errors are found — suitable for CI.
Add -q / --quiet to suppress success lines and emit only errors.
Manifest validation follows the canonical
contracts/plugin-manifest/plugin-manifest.schema.json: name, version, and
description are required; known contributes entries are shape-checked;
unknown contribution points remain forward-compatible. Daemon entries retain
the runtime's tolerant semantics: malformed daemon declarations are skipped by
the supervisor rather than making plugin installation fail.
Channel providers are plugins, not Core configuration records. The public
molecule_plugin.channel module owns the API v1 client contract: reserved
runtime environment names, canonical A2A request construction, response
parsing, and explicit unavailable/protocol/delivery-unknown failures. Core
does not own provider schemas. Generated channel scaffolds vendor that module
byte-for-byte so their daemon does not import private runtime code.
Programmatic equivalents:
from molecule_plugin import (
send_channel_message,
channel_message_response_text,
validate_plugin,
validate_workspace_template,
validate_org_template,
)
Per-runtime adaptors — when to write a custom one
The default AgentskillsAdaptor handles the common shape: rules go into the
runtime's memory file (CLAUDE.md), skill dirs go into /configs/skills/. That
covers most plugins.
Write a custom adaptor when you need to:
- Register runtime tools dynamically — call
ctx.register_tool(name, fn). - Register runtime sub-agents — call
ctx.register_subagent(name, spec). - Write to a non-standard memory file — call
ctx.append_to_memory(filename, content).
Minimum custom adaptor:
# adapters/codex.py
from molecule_plugin import InstallContext, InstallResult
class Adaptor:
def __init__(self, plugin_name: str, runtime: str):
self.plugin_name, self.runtime = plugin_name, runtime
async def install(self, ctx: InstallContext) -> InstallResult:
ctx.register_subagent("my-agent", {"prompt": "...", "tools": [...]})
return InstallResult(plugin_name=self.plugin_name, runtime=self.runtime, source="plugin")
async def uninstall(self, ctx: InstallContext) -> None:
pass
Resolution order (understood by the platform)
For (plugin_name, runtime):
- Platform registry —
workspace-template/plugins_registry/<plugin>/<runtime>.py(curated; set by the Molecule AI team for quality-assured plugins). - Plugin-shipped —
<plugin_root>/adapters/<runtime>.py(what this SDK helps you build). - Raw-drop fallback — copies plugin files into
/configs/plugins/<name>/and surfaces a warning; no tools are wired.
You generally ship for path #2. If your plugin becomes popular enough to be promoted to "default," the Molecule AI team PRs a copy of your adaptor into the platform registry (path #1) so it survives upstream breakage.
Runtime identifiers and official support
Runtime IDs are open, bounded, path-safe slugs defined by
contracts/adapter/runtime-id.schema.json; third-party adapters are not blocked
by a first-party allowlist. The separate official registry contains Claude Code,
Codex, Hermes, and OpenClaw. Known aliases such as claude_code normalize to
their canonical ID, while other valid IDs remain unchanged.
Build and test
pip install -e '.[test]' # base packages + pytest-asyncio
pytest -q