Module Boundaries & SDK Contract 🔴

OpenClaw uses explicit module boundaries to prevent architectural decay. This chapter explains the SDK contract, API baseline mechanism, and how boundaries are enforced.

Learning Objectives

After reading this chapter, you'll be able to:


I. Why Module Boundaries Matter

In large codebases, without explicit boundaries, "architectural decay" happens: plugins start importing internal core modules directly, creating tight coupling. This makes refactoring core nearly impossible.

OpenClaw's solution: The Plugin SDK is the only public interface. Plugins must only import from openclaw/plugin-sdk/* — never from src/ directly.


II. Plugin SDK Entry Points

src/plugin-sdk/entrypoints.ts lists all 20+ public entry points:

// Key entry points (simplified)
  'openclaw/plugin-sdk/core',              // Main entry (re-exports everything)
  'openclaw/plugin-sdk/channel-contract',  // Channel adapter types
  'openclaw/plugin-sdk/provider-entry',    // defineSingleProviderPlugin factory
  'openclaw/plugin-sdk/plugin-entry',      // definePlugin factory
  'openclaw/plugin-sdk/inbound-envelope',  // InboundEnvelope builder
  'openclaw/plugin-sdk/runtime',           // PluginRuntime types
  'openclaw/plugin-sdk/tool-contract',     // Tool definition types
  // ... 15+ more
];

core.ts is a 21KB Re-Export File

src/plugin-sdk/core.ts doesn't contain logic — it's a single file that re-exports everything from all other entry points:

// src/plugin-sdk/core.ts (simplified)
// ... 20+ more exports

Why? Convenience. Plugin developers can import everything from one place:


III. API Baseline: Preventing Breaking Changes

src/plugin-sdk/api-baseline.ts (495 lines) implements a snapshot-and-diff CI mechanism:

Dev makes changes to SDK
  → npm run check:api-baseline
  → Snapshot current public API surface
  → Diff against committed baseline.json
  → If any PUBLIC signatures changed → CI FAILS
  → Developer must explicitly update baseline (with reason)

This forces breaking changes to be intentional and documented — preventing accidental API breakage that would break plugins.


IV. sdk-alias as Technical Enforcement

The sdk-alias mechanism (used in jiti plugin loading) is the technical enforcement of module boundaries:

When a plugin code does:

jiti intercepts this and resolves it to the actual core runtime file. If a plugin tries to do:

This would fail at runtime (path doesn't exist from plugin's perspective) and fail in TypeScript compilation (not in types).


V. Boundary Rules Summary

LayerCan Import FromCannot Import From
Pluginopenclaw/plugin-sdk/*src/* directly
src/plugin-sdk/src/ internal modulesExternal plugins
src/gateway/src/routing/, src/plugins/, src/agents/extensions/*
src/agents/src/infra/, src/config/, src/routing/src/gateway/

These rules are documented in AGENTS.md / CLAUDE.md files in each directory.


Key Source Files

FileSizeRole
src/plugin-sdk/core.ts21KBSDK main entry (re-exports all public APIs)
src/plugin-sdk/entrypoints.ts-All SDK entry point definitions
src/plugin-sdk/api-baseline.ts495 linesAPI baseline check (CI)
src/plugin-sdk/channel-contract.ts-Channel adapter type contracts
src/plugin-sdk/AGENTS.md-SDK boundary rules for AI coding assistants

Summary

  1. Plugins can only import from openclaw/plugin-sdk/* — never from src/ internals.
  2. 20+ SDK entry points — all re-exported from core.ts for convenience.
  3. API Baseline CI check — ensures breaking changes are intentional and documented.
  4. sdk-alias is technical enforcementjiti intercepts imports and routes them correctly.
  5. AGENTS.md files document boundary rules for AI coding assistants.

← Plugin System | → Message Lifecycle