Skip to main content

Packages

Peers packages are how the app loads extensible behavior: tables and tools (and related metadata) on the server/runtime side, routes for URL mapping in the browser, and UI bundles for React screens. The desktop app and PWA install package versions from bundled assets or synced updates, then activate a version per data context (personal space or group).

At a high level, a package contributes:

  • Runtime (Node / Electron main, or PWA runtime) — table definitions, tool instances, assistants, workflows, and navigation metadata (appNavs).
  • Routes — small bundle that registers URL paths before UI loads.
  • UI — lazy-loaded React components registered by peersUIId.

Package lifecycle

Packages follow a three-phase lifecycle: devbetastable.

PhaseHow it's createdWho sees it
devAutomatically when code is loaded from diskOnly the local device — never auto-activates on other devices
betaPromoted via the UI or promote-package-version toolDevices following stable+beta
stablePromoted via the UI or promote-package-version toolAll devices (default follow policy)

Key points:

  • Disk updates always create dev versions. The versionTag is determined by the platform, not set in code.
  • Dev versions are device-local. They sync to the group but never auto-activate on other devices unless a device explicitly opts in.
  • Promotion is explicit. Use the promote button in the package versions UI, or call the promote-package-version tool from a CI pipeline or AI assistant.
  • Writers can create dev versions. Only Admins can promote to beta or stable.
  • Contracts are finalized on stable promotion. When a package version is promoted to stable, all its dev contracts are frozen (immutable).

See Package lifecycle design for the full design rationale and implementation details.

Defining a package

Use definePackage() from @peers-app/peers-sdk to declare a package:

import { definePackage } from "@peers-app/peers-sdk";
import { version } from "../package.json";

const packageDefinition = definePackage((pkg) => {
pkg.packageId = packageId;
pkg.version = version;

const main = pkg.contract(contractId, 1, "My App");
main.tables = [/* table definitions */];
main.tools = [/* tool instances */];
main.toolInstances = [/* executable tool instances */];
main.tableDefinitions = [/* runtime table definitions */];

pkg.appNavs = [{
name: "My App",
iconClassName: "bi bi-app",
navigationPath: "app",
}];
});

(exports as any).packageDefinition = packageDefinition;

Note: versionTag and contract devTag are not set in code. The platform assigns these based on the package's promotion state.