Development Workflow
From finishing code to merging into main, there are several checkpoints: local build and test, the complete harness suite, changeset, and CI publishing. This page walks through the day-to-day workflow in that order.
Collaboration
Describe the problem and acceptance criteria in an issue, then link the implementation PR. The delivery board tracks active issues and PRs through Todo → In Progress → Done. New or updated open items are added automatically; historical merged PRs do not need backfilling. The GitHub Wiki is a documentation entry point; the maintained technical content lives in this repository's docs/ directory.
Environment Setup
- Node.js
^20.19.0or>=22.12.0 - pnpm 9 (repo pins
packageManager: pnpm@9.0.2)
pnpm install # Install all workspace dependenciesCommon Commands
pnpm dev # Start examples/minimal-bot (Sandbox + Console); recommended for first-time verification
pnpm dev:full # Start examples/full-bot (L4 reference)
pnpm dev:test # Start examples/test-bot (maintainer kitchen sink)
pnpm build # Turbo builds all packages in order: basic -> packages -> plugins
pnpm test # Full Vitest run
pnpm type-check # tsc --noEmit (tsconfig.typecheck.json)
pnpm lint # ESLintWhen verifying a single package, prefer pnpm --filter <pkg> build|test instead of running a full build by default.
If you get an error about @zhin.js/scaffold-wizard not being found before working on CLI or create-zhin-app, build it first (output goes to lib/; Node cannot resolve it before building):
pnpm --filter @zhin.js/scaffold-wizard build # or pnpm prepare:cliHarness CI Gates (pnpm check:all)
The most valuable command to run before committing is pnpm check:all: it runs every check registered in scripts/check-all-harness.mjs (including type-check, lint, and unit tests). All must pass to go green -- CI runs the exact same suite. If CI runs a separate coverage job, you can set HARNESS_SKIP_TEST=1 to skip the pnpm test portion and avoid running tests twice.
Below are the checks grouped by responsibility (the command in parentheses can be run individually).
Quality Baseline
| Check | Description |
|---|---|
Type Check (pnpm type-check) | tsc --noEmit |
Lint (pnpm lint) | ESLint (.ts/.tsx) |
Unit Tests (pnpm test) | Full Vitest run |
Production Config (pnpm check:prod) | No debug code in production config |
Architecture & Dependencies
| Check | Description |
|---|---|
Architecture Layers (pnpm check:architecture) | Layer dependency direction (basic -> kernel -> ai -> core -> agent -> zhin) |
Dependency Policy (pnpm check:dependency-policy) | Scaffold dependency policy, Changesets config, and internal peer ranges |
Release Plan (pnpm check:release-plan) | Patch-only by default; minor/major require an owner approval record |
No Koa Import (pnpm check:no-koa) | Plugins must not directly import koa |
Install Size (pnpm check:install-size) | zhin.js IM core production node_modules <= 10MB |
API Snapshots & Plugin Spec
| Check | Description |
|---|---|
API Surface (pnpm check:api-surface) | Public API surface snapshot |
Plugin Runtime API (pnpm check:plugin-runtime-api) | Convention-based plugin runtime API surface snapshot |
Plugin Spec (pnpm check:plugin) | Plugins conform to standard spec |
Plugin Capability Publish (pnpm check:plugin-capability-publish) | Plugins publish their capability directories with the required files, prepublish build, and peer dependencies |
Publish Repository (pnpm check:publish-repository) | Publishable packages have repository.url matching github.com/zhinjs/zhin (npm provenance) |
Agent Tool Schema (pnpm check:agent-tool-schema) | tools inputSchema matches defineAgentTool/execute types |
Skill Authoring Boundaries (pnpm check:skill-authoring-boundaries) | Skills use skills/<name>/SKILL.md and explicitly mount the Feature |
IM Chain & Runtime Conventions
| Check | Description |
|---|---|
IM Send Path (pnpm check:harness-paths) | Must not bypass the Adapter.sendMessage unified chain |
IM Session SSOT (pnpm check:im-session-ssot) | IM scene/session identity resolution uses core SSOT |
Removed Plugin API (pnpm check:no-removed-plugin-api) | Removed Plugin lookup APIs must not reappear in production source |
Workroom SSOT (pnpm check:workroom-ssot) | Workroom state must go through the Journal + CAS Kernel; parallel mutable authorities are forbidden |
AI Layer
| Check | Description |
|---|---|
LLM Runtime Boundaries (pnpm check:llm-runtime-boundaries) | Runtime code resolves models through an owner-scoped LlmApiRuntime and does not import ambiguous getModel |
Legacy AI Exports (pnpm check:legacy-ai-exports) | @zhin.js/ai no longer exports SessionManager and similar symbols |
Provider Gateway (pnpm check:provider-gateway) | LLM gateway sdk/contextWindow preset contract |
A2A Mesh (pnpm check:a2a-mesh) | No residual MCP Agent Mesh v1 symbols |
Adapter Contracts
| Check | Description |
|---|---|
Outbound Media Policies (pnpm check:outbound-media-policies) | segments.outboundMedia declarations and contract tests |
AI Outbound Adapters (pnpm check:ai-outbound) | aiOutboundExtensions declaration and contract tests |
Interactive Segments (pnpm check:interactive-segments) | interactivePolicy declaration and contract tests |
Segment Adapters (pnpm check:segments) | defineAdapter segments declaration contract (sandbox must pass) |
Documentation Consistency
| Check | Description |
|---|---|
Doc Links (pnpm check:doc-links) | Documentation relative links are not broken |
Doc Orphans (pnpm check:doc-orphans) | All site Markdown files are in sidebar or allowlist |
ADR Manifest (pnpm check:adr-manifest) | ADR README and sidebar cover all ADRs |
README Exports (pnpm check:readme-exports) | README imports match package exports |
Config Docs (pnpm check:config-docs) | Config documentation aligns with DEFAULT_CONFIG key fields |
Generated Config Reference (pnpm check:config-reference) | Generated configuration fields stay aligned with Runtime source and plugin JSON Schema |
Source-owned Config Enums (pnpm check:config-enums) | Source-owned configuration enums stay aligned across Runtime/plugin Schema, generated reference, and narrative docs |
Troubleshooting Center (pnpm check:troubleshooting) | The incident catalog stays aligned with bilingual Symptom → Cause → Action → Verification pages |
Install Tiers SSOT (pnpm check:install-tiers-ssot) | Chinese README.zh-CN.md Install tiers table matches docs/snippets/install-tiers.md |
Adapter Docs Sync (pnpm check:adapter-docs) | Platform adapter docs sync with plugins/adapters/*/README.md (fix with pnpm sync:adapter-docs) |
Platform Tiers SSOT (pnpm check:platform-tiers-ssot) | Capability tiers/adapter index matches scripts/adapter-meta.mjs |
Deployment Templates (pnpm check:deployment-templates) | Compose, systemd, and Kubernetes templates match their Chinese and English download entries |
Smoke Tests
| Check | Description |
|---|---|
Stable Smoke (pnpm check:stable) | Sandbox + Agent core unit tests + minimal-bot contract |
L4-CI (pnpm check:l4-ci) | L4 deterministic subset (orchestration/memory/full-bot contract); full pnpm check:l4 runs nightly |
Changeset Workflow
The repo uses changesets for version management and changelogs (config in .changeset/config.json: baseBranch: main, access: public). Any change that affects the behavior of a published package must include a changeset:
pnpm release # = pnpm changeset; interactively select affected packages and semver level, generates .changeset/*.md
pnpm bump # = pnpm changeset version; consumes changesets, bumps version numbers, writes CHANGELOG
pnpm pub # = pnpm changeset publish; publishes to npmDuring daily development you only need pnpm release to commit the changeset file; bump and pub are executed by CI.
The default release policy permits patch releases only. pnpm check:release-plan inspects the complete Changesets plan and fails on any unapproved minor or major, including bumps inferred through dependency propagation. A non-patch release requires the version owner to record the changeset filename, package scope, release type, approver, and reason in .changeset/version-policy.json. .github/CODEOWNERS assigns owner review for that policy file. Release coverage deliberately ignores only tests and Changesets-generated CHANGELOG.md files. Package-local build, type-check, and tooling configuration can change emitted code or declarations, so those configuration changes also require a patch changeset.
Internal peer dependencies use workspace:^ so compatible internal releases publish as caret ranges instead of exact versions. Private examples do not participate in Changesets versioning or tags.
1.1 stable line
The official npm ecosystem uses the 1.1.x stable line. Eighty-one packages whose 1.1.0 version was still available start at 1.1.0. Seven packages that had already published 1.1.0 use their next available 1.1.x patch because npm does not permit version reuse. Historical higher versions remain available to preserve existing lockfiles and are marked as superseded by the corresponding 1.1.x stable release. Each official package points both latest and stable to that release; routine releases then increment patch only.
| Package whose 1.1.0 is reserved | Stable version |
|---|---|
@zhin.js/adapter | 1.1.12 |
@zhin.js/agent | 1.1.23 |
@zhin.js/ai | 1.1.33 |
@zhin.js/client | 1.1.5 |
@zhin.js/console-protocol | 1.1.5 |
@zhin.js/core | 1.1.35 |
@zhin.js/plugin-runtime | 1.1.9 |
Publishing (GitHub CI)
Publishing is driven by .github/workflows/publish.yml: on push to main or via Actions → workflow_dispatch.
First publish for new packages
npm no longer allows this pipeline to create a package name for the first time. Maintainers must publish once with a token; later versions go through changesets.
pnpm check:unpublished
pnpm build
(cd path/to/pkg && npm publish --access public)Then re-run Build and Publish (push main or workflow_dispatch).
PR gates are in .github/workflows/ci.yml (Node 22/24 matrix), which also runs pnpm check:all.
Debugging
- Log level: Set
log_leveltodebuginzhin.config.yml(default isinfo) to see detailed framework internal logs. - Console logs page: Runtime logs are written to the
SystemLogdatabase model viaDatabaseLogTransport. The Remote Console logs page reads from it. Open console.zhin.dev in your browser, fill in the API Base URL (e.g.http://127.0.0.1:8086) and Bearer Token (http.tokenconfig) to view. - Single-package debugging:
pnpm --filter <pkg> testwith-t '<test name>'to filter tests;pnpm test:watchto enter watch mode.