@xtrape/capsule-contracts-node
Xtrape Contracts for Node.js
TypeScript contracts and Zod schemas for Xtrape Agent, Worker, and Panel wire protocols.
The npm name @xtrape/capsule-contracts-node is a legacy compatibility
identifier. Capsule is not a current Xtrape concept. New code should use the
canonical Worker* exports; the existing Capsule* exports and services wire
field remain available until a versioned protocol migration removes them.
Contract Authority Boundary
| Name | Role |
|---|---|
xtrape-contracts |
The future language-neutral schema authority for Xtrape contracts (not yet a separate repository). |
xtrape-contracts-nodejs (this repo) |
The TypeScript / Zod runtime validation and type implementation. |
Until a standalone xtrape-contracts exists, this package hosts the executable
TypeScript schemas, but it is not a separate conceptual authority: the
canonical model lives in xtrape-docs
(runtime-platform/02..04, architecture/11). When the two disagree, the
canonical architecture docs win and this package is corrected to match.
Xtrape CE 0.1 Phase 0 Contracts
The CE 0.1 runtime loop (Telegram → server-ce → demo xtrape-service → reply)
depends on a frozen set of schemas, exported from this package and validated
by tests/ce-contracts.spec.ts (including a field/enum surface guard):
| Export | Used by |
|---|---|
CE_CONTRACT_VERSION (1) |
version negotiation across agent server-ce |
ServiceManifestSchema / ServiceManifest |
service registration descriptor |
ServiceInstanceSchema / ServiceInstance |
registered instance with resolvable address |
AgentHeartbeatSchema / AgentHeartbeat |
heartbeat / health reporting |
ConversationMessageSchema / ConversationMessage |
message routing + reply envelope |
ErrorModelSchema / ErrorModel (+ CeErrorCode) |
structured error responses |
import { ServiceManifestSchema, CE_CONTRACT_VERSION } from "@xtrape/capsule-contracts-node";
const manifest = ServiceManifestSchema.parse({
contractVersion: CE_CONTRACT_VERSION,
service: { id: "demo-echo-service", name: "Demo Echo Service", version: "0.6.0" },
runtime: { language: "node", agent: "xtrape-agent-nodejs" },
capabilities: ["status.query"],
message: { supportedTypes: ["QUERY"] },
});These schemas are frozen for CE 0.1: changing a field or enum is a contract
change that must bump CE_CONTRACT_VERSION and update the surface guard. See the
matching examples in xtrape-docs/docs/runtime-platform/01-phase-0-runtime-mvp.md.
@xtrape/capsule-contracts-node is the current published TypeScript contract
package for Panel CE, Agent SDKs, and Worker integrations. It exports Zod
schemas, inferred TypeScript types, enum values, ID helpers, pagination helpers,
and protocol error helpers for the Agent/Admin/System wire contracts.
Package status: This package follows the unified Xtrape
0.6.0release train. The npm package name remains a compatibility identifier, but release versioning now follows the shared Xtrape train version.
Install
This repository tracks the 0.6.0 snapshot train. Until the 0.6.0 npm cut is
published, install the latest published compatibility package:
pnpm add @xtrape/capsule-contracts-node@^0.5.1For this repository itself:
pnpm install
pnpm buildWhat is Included
The package currently exports:
- Zod itself as
zfor consumers that want one compatible Zod instance. - Status enum arrays and types:
AgentStatus,WorkerStatus(plus the legacyCapsuleServiceStatusalias),HealthStatus,CommandStatus,DangerLevel,AuditActorType,AuditResult,TokenStatus,AgentMode. - Admin schemas: users, sessions, registration token requests/responses.
- Agent schemas: registration, heartbeat, service report, command result.
- Worker schemas: Worker Manifest, Worker Runtime Report, Worker Instance, health, config, Action, and Worker Instance detail. Legacy Capsule-named aliases remain available for wire compatibility.
- Command schemas: create command, command detail, command result.
- Audit and dashboard schemas.
- System health/version schemas.
The additive v0.4 Worker endpoint aliases and their legacy mappings are recorded
in spec/worker-compatibility-v0.4.json. The older CE v0.1 OpenAPI file remains
the historical baseline rather than being silently rewritten into a different
protocol version.
Known contract drift: the historical structured sources still disagree on some Command and effective-status enum values. The
WorkerStatusexport is an alias of the currently shipped binding; it does not claim that the unresolved enum migration documented inxtrape-docshas been completed.
- Helpers:
parseSort,paginate,HttpError,ListQueryBase.
Validate Agent Registration
import { RegisterAgentRequestSchema } from "@xtrape/capsule-contracts-node";
const request = RegisterAgentRequestSchema.parse(input);
// request.registrationToken starts with opstage_reg_
// request.agent.mode is embedded or ophubLowercase aliases are also exported for backend compatibility:
import { registerAgentRequestSchema } from "@xtrape/capsule-contracts-node";
const request = registerAgentRequestSchema.parse(input);v0.3 External-Agent Compatibility and Metadata
v0.3 adds the legacy ophub Agent-mode wire value for the historical Go
external-Agent runtime. It represents one or more local Workers. It is not the
canonical Gateway role: Gateway routes Agent/control-plane traffic while
preserving Agent protocol semantics.
import { RegisterAgentRequestSchema, ServiceReportRequestSchema } from "@xtrape/capsule-contracts-node";
RegisterAgentRequestSchema.parse({
registrationToken: "opstage_reg_...",
agent: {
code: "ophub-a",
name: "External Agent A",
mode: "ophub",
runtime: "go",
},
});
ServiceReportRequestSchema.parse({
services: [
{
code: "svc-one",
name: "Service One",
version: "0.3.0",
runtime: "nodejs",
manifest: {
kind: "CapsuleService",
code: "svc-one",
name: "Service One",
version: "0.3.0",
runtime: "nodejs",
agentMode: "ophub",
capabilities: [{ name: "inventory.read", label: "Inventory read" }],
events: [{ name: "inventory.changed", direction: "publish", designOnly: true }],
},
},
],
});Capability metadata is implemented as declarative service metadata. Event
metadata is intentionally a foundation for future legacy event routing work; designOnly
events must not be treated as a working event bus.
Validate Service Report
import { ServiceReportRequestSchema } from "@xtrape/capsule-contracts-node";
const report = ServiceReportRequestSchema.parse({
services: [
{
code: "hello-capsule",
name: "Hello Capsule",
version: "0.1.0",
runtime: "nodejs",
manifest: {
kind: "CapsuleService",
schemaVersion: "1.0",
code: "hello-capsule",
name: "Hello Capsule",
version: "0.1.0",
runtime: "nodejs",
agentMode: "embedded",
},
},
],
});Validate Health Report
import { HealthReportInputSchema } from "@xtrape/capsule-contracts-node";
const health = HealthReportInputSchema.parse({
status: "UP",
message: "ok",
details: { uptimeSeconds: 123 },
});Allowed health statuses are:
import { HealthStatus } from "@xtrape/capsule-contracts-node";
console.log(HealthStatus); // ["UP", "DEGRADED", "DOWN", "UNKNOWN"]HealthStatus is the protocol-level status reported by Agents and Capsule
Services:
UPDEGRADEDDOWNUNKNOWN
Xtrape Panel may derive an operator-facing effectiveStatus such as:
HEALTHYUNHEALTHYSTALEOFFLINE
Validate Config and Action Definitions
import {
ConfigItemInputSchema,
ActionDefinitionInputSchema,
} from "@xtrape/capsule-contracts-node";
const config = ConfigItemInputSchema.parse({
key: "UPSTREAM_BASE_URL",
type: "string",
sensitive: false,
valuePreview: "https://api.example.test",
});
const action = ActionDefinitionInputSchema.parse({
name: "reload-cache",
label: "Reload Cache",
dangerLevel: "MEDIUM",
requiresConfirmation: true,
});Validate Action Prepare Result
Use ActionPrepareResultSchema to validate the action-prepare payload directly:
import { ActionPrepareResultSchema } from "@xtrape/capsule-contracts-node";
const prepare = ActionPrepareResultSchema.parse({
initialPayload: { message: "hello" },
currentState: { service: "ready" },
inputSchema: {
type: "object",
properties: {
message: { type: "string", default: "hello" },
},
},
});When reported back to Xtrape Panel for an ACTION_PREPARE command, this shape is
placed under ReportCommandResultRequest.data. Command result reporting still
uses ReportCommandResultRequestSchema:
import { ReportCommandResultRequestSchema } from "@xtrape/capsule-contracts-node";
const prepareResult = ReportCommandResultRequestSchema.parse({
success: true,
data: {
action: { name: "echo", label: "Echo", dangerLevel: "LOW" },
inputSchema: {
type: "object",
properties: { message: { type: "string", default: "hello" } },
},
initialPayload: { message: "hello" },
currentState: { service: "ready" },
},
});Validate Command Result
import { ReportCommandResultRequestSchema } from "@xtrape/capsule-contracts-node";
const result = ReportCommandResultRequestSchema.parse({
success: true,
message: "Done",
data: { count: 1 },
startedAt: new Date().toISOString(),
finishedAt: new Date().toISOString(),
});Failed results should include an operator-safe message and structured error:
ReportCommandResultRequestSchema.parse({
success: false,
message: "Provider challenge page detected.",
error: {
code: "ACTION_FAILED",
retryable: false,
},
});Error Codes
The ErrorCode export contains protocol-level error code constants currently
used by CE and SDKs:
import { ErrorCode } from "@xtrape/capsule-contracts-node";
throw new Error(ErrorCode.VALIDATION_FAILED);Currently exported codes include:
INTERNAL_ERRORVALIDATION_FAILEDUNAUTHORIZEDFORBIDDENNOT_FOUNDCONFLICTCAPSULE_SERVICE_CODE_TAKEN(persisted compatibility identifier for a Worker ownership conflict)CSRF_INVALIDACTION_REQUIRES_CONFIRMATIONCOMMAND_EXPIREDTOKEN_REVOKEDTOKEN_EXPIREDAGENT_REVOKEDAGENT_DISABLED
See the OpenAPI contract and docs site for endpoint-specific errors.
ID generation
This package validates IDs at the wire boundary (via Zod) but does not mint
them. Until v0.1.x there was a small newId() helper plus an idPrefixes
table; both were removed in 0.2.0 to keep the contracts surface focused on
the wire spec — see CHANGELOG.md and the
"Breaking changes" section at the top of this README.
Consumers that need local ID generation should provide their own factory.
Example using nanoid directly:
import { customAlphabet } from "nanoid";
const idBody = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 21);
const commandId = `cmd_${idBody()}`;Documented ID prefixes in use across CE and the Agent SDK include wks_,
usr_, agt_, tok_, svc_, hlr_, cfg_, act_, cmd_, crs_, and
aud_. These are enforced by the Zod schemas via z.string().startsWith(...).
List Helpers
import {
ListQueryBase,
parseSort,
paginate,
} from "@xtrape/capsule-contracts-node";
const query = ListQueryBase.parse({ page: "1", pageSize: "20" });
const sort = parseSort("-createdAt", ["createdAt", "name"]);
const response = paginate(items, query.page, query.pageSize, total);Used By
xtrape-panel-ce— Xtrape Panel CE backend validation and protocol handling.xtrape-agent-nodejs— Node embedded Agent SDK request/response types.xtrape-demo— End-to-end runnable Worker that imports these schemas through the Agent SDK.- Worker implementations that want local validation before reporting to Xtrape Panel.
Compatibility
| Package | Compatible with |
|---|---|
@xtrape/capsule-contracts-node@0.2.x |
Xtrape Panel CE 0.2.x and Agent SDK 0.2.x |
@xtrape/capsule-contracts-node@0.1.x |
Xtrape Panel CE 0.1.x and Agent SDK 0.1.x |
Pin matching minor versions across CE, Agent SDK, and Contracts. The wire
protocol may still evolve before v1.0.
Breaking changes in 0.2.0
newId()removed. The helper minted random IDs with a prefix; it was never used by CE (entity IDs are minted in the backend). External consumers that importednewIdmust wire their own factory — see the ID generation section above.idPrefixesconstant andIdPrefixtype removed. Same rationale.nanoidruntime dependency removed as a consequence. Consumers that relied on a transitivenanoidinstall must now add it directly.
The wire schemas themselves are unchanged between 0.1.x and 0.2.x;
existing 0.1.x agents continue to validate against a 0.2.x backend.
Schema Stability
The package follows semver. During the current pre-1.0 release-train phase,
the guarantees per schema group are:
| Group | Stability | Notes |
|---|---|---|
Status enums (AgentStatus, CapsuleServiceStatus, HealthStatus, CommandStatus, DangerLevel, TokenStatus) |
Stable | New values may be added in minor versions; existing values will not be removed before v1.0. |
Agent Backend wire schemas (RegisterAgentRequest, AgentHeartbeat*, ServiceReport*, ReportCommandResult*) |
Evolving | Field shape is stable; additive optional fields may land in minor versions. Required fields will not be added before v1.0 without a deprecation cycle. |
Worker shapes (WorkerManifest, WorkerRuntimeReport, WorkerInstance, HealthReportInput, ConfigItemInput, ActionDefinitionInput) |
Evolving | Legacy aliases retain the existing physical wire shapes. |
Persisted shapes (Agent, CapsuleService, ConfigItem, ActionDefinition, Command*, AuditEvent, User) |
Evolving | Track CE storage; safe to consume read-only. |
ActionPrepareResultSchema |
Provisional | Added in 0.1.0-public-review.0. Field shape may still tighten before v1.0. |
Command.type enum |
Evolving | Currently ACTION_PREPARE / ACTION_EXECUTE. New types may be added. |
Error codes (ErrorCode) |
Evolving | New codes may be added. Existing codes will not change meaning before v1.0. |
Helpers (parseSort, paginate, HttpError, ListQueryBase) |
Provisional | Helpful for backend-style consumers but not strictly part of the wire spec; may move to a separate utility package in a future minor. (newId / idPrefixes / IdPrefix were removed in 0.2.0 — see "Breaking changes in 0.2.0" above.) |
Until v1.0, pin to a single minor across CE / Agent SDK / Contracts.
Breaking changes will be called out in CHANGELOG.md.
Documentation
- Public docs repo: https://forgejo.xtrape.com/xtrape/xtrape-site
- Contracts overview: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/contracts/overview.md
- Manifest contract: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/contracts/manifest.md
- Health contract: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/contracts/health.md
- Actions contract: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/contracts/actions.md
- Errors: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/contracts/errors.md
- Xtrape Panel CE docs: https://forgejo.xtrape.com/xtrape/xtrape-site/src/branch/main/docs/opstage-ce/overview.md
Contributing
See CONTRIBUTING.md for schema change workflow and PR checks. See SECURITY.md for vulnerability reporting and contract validation safety guidance.
License
Apache-2.0. "Xtrape" and "Opstage" are trademarks of their respective owners; the open-source license does not grant trademark rights.
v0.4 legacy event routing Experimental
v0.4 adds an experimental legacy event routing contract surface for CE's built-in SQLite-backed in-process event-to-command router. It is intentionally small, single-node, and disabled by default; it is not a standalone Bus Server, external broker (NATS / RabbitMQ / Redis Streams / Kafka), workflow DSL, or service mesh. No fan-out (maxCommandsPerEvent) in v0.4 — one matched route produces at most one ACTION_EXECUTE command.
Key exports:
BusEventEnvelopeSchemaPublishBusEventRequestSchemaPublishBusEventResponseSchemaBusRouteRuleSchemaCreateBusRouteRuleRequestSchema
Minimal event payload:
BusEventEnvelopeSchema.parse({
eventType: "demo.item.created",
sourceServiceCode: "demo-worker",
payload: { itemId: "item-1" },
});All schemas include or default experimental: "v0.4-experimental"; consumers should treat the wire surface as unstable until v1.0.