Skip to content

Public API Surface

This checklist is the SSOT (single source of truth) for determining whether an API is public or internal. The goal: a maintainer can make a judgment on any symbol within 10 minutes without reading the implementation.

Three tiers:

TierLabelMeaning
Stable Publicstable / experimentalUser-facing authoring surface, commits to semver (experimental may be adjusted in minor releases, with prior notice in the changelog)
InternalinternalFramework internals. Readable and debuggable, but no guarantee against breaking changes -- may change in any version
DeprecateddeprecatedMigrated/no longer recommended. Kept for compatibility for one minor cycle then removed

Annotation location: source JSDoc (@public / @internal) should be annotated in entry files first; this checklist is the complete list. When they conflict, this checklist takes precedence and a PR should be filed to correct the source.

Stable Public (semver commitment)

define* Authoring Functions

APIStabilitySource PackageOne-liner
definePluginstable@zhin.js/plugin-runtimeConvention-based plugin entry, default export from plugin.ts
defineCommandstable@zhin.js/commandCommand module (default export in commands/)
defineAdapterstable@zhin.js/adapterAdapter module (default export in adapters/), create(context) returns an Endpoint
defineComponentstable@zhin.js/componentSatori/SSR component (default export in components/)
defineMiddlewarestable@zhin.js/middlewareMiddleware module (default export in middlewares/)
defineAgentToolexperimental@zhin.js/tool (tools/ convention); zhin.js/agent (agent/tools/*.ts authoring surface)AI tool module, auto-discovered by Agent

Note: There is no defineAgentSkill. Agent skills are pure Markdown (agent/skills/*.md, parsed by parseSkillMarkdown from @zhin.js/skill), not code symbols.

Convention Directories and Files

ConventionStabilityConsumerOne-liner
plugin.tsstable@zhin.js/plugin-runtimePlugin root entry, default exports definePlugin(...)
commands/stable@zhin.js/commandCommand module directory, supports [name:type] dynamic parameter segments
adapters/stable@zhin.js/adapterAdapter module directory
middlewares/stable@zhin.js/middlewareMiddleware module directory
tools/experimental@zhin.js/toolAgent tool directory (defineAgentTool)
agent/toolsexperimentalzhin.js/agent authoringFile-based Agent tool authoring surface
agent/skillsexperimental@zhin.js/skill / Agent discoveryAgent skill Markdown (published with npm packages)
pages/experimental@zhin.js/console-pageConsole page module directory

Host Tokens (consumed via context.resources.use(token))

TokenStabilitySource PackageOne-liner
databaseHostTokenstable@zhin.js/plugin-runtimeDatabase Host capability
scheduleHostTokenstable@zhin.js/plugin-runtimeScheduled task Host capability
outboundHostTokenstable@zhin.js/plugin-runtimeCross-platform outbound message capability
agentToolsHostTokenexperimental@zhin.js/plugin-runtimeAgent tool registration Host capability
messageGatewayTokenstable@zhin.js/core (zhin.js/core/runtime)Inbound message delivery gateway (used by adapters)
httpHostTokenstable@zhin.js/host-httpHTTP/WS Host capability (used by Console, Webhooks)

Legacy Hooks (Kept for Compatibility)

APIStabilitySource PackageOne-liner
usePlugin() and associated hooks (provide / addCommand / useContext, etc.)deprecated (see table below)zhin.js (@zhin.js/core)Legacy plugin system entry, still compatible; new code uses convention-based approach
MessageCommand / CommandFeaturedeprecatedzhin.js (@zhin.js/core)Classic commands; new code uses defineCommand + commands/
bootstrapNode / zhin.js/nodedeprecatedzhin.js/nodeClassic Host startup; not wired to CLI; new code uses zhin runtime start

zhin.config.yml Top-Level Keys

KeyStabilityConsumerOne-liner
plugins.<key>stable@zhin.js/cli assembly layerPlugin enablement and plugin-level config
endpoints[i]stable@zhin.js/cli assembly layerAdapter instance list (includes master / trusted / commandPrefix)
commandPrefixstableMessageDispatcherCommand prefix, top-level instance + per-endpoint override
aistable@zhin.js/cli AI Host assemblyAI/Agent configuration
httpstable@zhin.js/host-http assemblyHTTP Host configuration
databasestabledatabase Host assemblyDatabase configuration
speechstablespeech Host assemblySpeech configuration
log_levelstable@zhin.js/cliLog level (ZHIN_LOG_LEVEL can override)

Other Host-level keys (mcp / a2a / htmlRenderer / assistant / collaboration) are also stable top-level keys; see Configuration Overview for the complete table.

CLI Commands

CommandStabilitySource PackageOne-liner
zhin runtime startstable@zhin.js/cliPlugin Runtime entry point (composition root)
zhin setupstable@zhin.js/cliIncremental configuration wizard for existing projects
zhin doctorstable@zhin.js/cliEnvironment/config health check
pnpm create zhin-appstablecreate-zhin-appNew project scaffold

Internal (Readable but No Stability Guarantee)

APIStabilitySource PackageOne-liner
RootRuntime / RootControllerinternal@zhin.js/plugin-runtimeRoot controller for plugin tree and generations
CapabilitySlotinternal@zhin.js/plugin-runtimeCapability slot, carrier between features and projections
SnapshotStore / RuntimeSnapshotinternal@zhin.js/plugin-runtimeAtomic snapshot store, input for projections
AdapterIndexinternal@zhin.js/adapterAdapter projection, snapshot -> Endpoint assembly
CommandIndexinternal@zhin.js/commandCommand projection, snapshot -> command routing table
ToolIndex / SkillIndex / McpIndex / PageIndex / LayoutIndex, etc.internalVarious feature packagesOther projections, all internal mechanisms
defineFeatureProvider (Feature Provider protocol)internal@zhin.js/feature-kitProtocol for adding new feature types, aimed at framework extenders, not plugin authors
MessageDispatcherinternal@zhin.js/coreMessage dispatcher (createMessageDispatcher for assembly, routing strategy is configurable)
basic/cli/src/plugin-runtime/*-installer.tsinternal@zhin.js/cliRoot Host installers (database / schedule / outbound / inbox / http / console / agent / speech / html-renderer / protocol); assembly details may change at any time

Deprecated / Migrated

ItemStabilityStatusOne-liner
Legacy usePlugin() plugin systemdeprecatedKept for compatibility, runtime still supports itNew code uses convention-based approach (plugin.ts + convention directories); deletion countdown begins after dual-track migration is complete
MessageCommand / classic CommandFeaturedeprecatedStill used by Agent init / game-kit hubWill be removed after migration to defineCommand + Runtime CommandIndex
bootstrapNode / zhin.js/nodedeprecatedKept for compatibility, not wired to CLIUse zhin runtime start instead; will be removed after at least one minor version
"Host plugin" narrativedeprecatedDocumentation has been consolidatedHost capabilities are now token-based (see Host Token table above), no longer a plugin concept
examples/test-bot as a user pathdeprecatedMaintainer kitchen sinkUser paths are minimal-bot (Stable) -> full-bot (L4); do not use test-bot config as a template
plugin.yml plugin manifestdeprecatedLegacy Plugin and zhin build still read it (packages/im/core/src/plugin.ts, basic/cli/src/libs/plugin-package-build.ts)Part of the legacy system, will be retired along with it; convention-based plugins use package.json as the source of truth

Decision Rules (Which Tier for New APIs)

Ask three questions in order:

  1. Is this something a plugin author/user would write directly? (define* functions, convention directories, config keys, CLI commands, Host tokens) -> Yes: default to Stable Public. AI/Console and other surfaces that haven't converged yet should be labeled experimental first, then promoted to stable after convergence.
  2. Is this a mechanism in the snapshot -> projection -> assembly pipeline? (*Index, SnapshotStore, CapabilitySlot, installer, dispatcher, Feature Provider protocol) -> Yes: default to Internal. Internal mechanisms do not become public just because they are exported (for cross-package reuse).
  3. Removing/replacing an existing public API? -> First label deprecated (JSDoc @deprecated + move in this checklist + note in changelog), keep for at least one minor cycle before removal; removal itself is a breaking change, handled via major bump or per the repo's release conventions.

Fallback: when in doubt, treat it as Internal -- promoting from internal to public does not break anyone; the reverse is a breaking change.

Related docs: Code Conventions, Development Workflow & CI Gates, Plugin Model.