Skip to main content
Version: 3.1

App Store

The App Store is the distribution and runtime layer for Operaide Apps. As a developer, it is how your code gets from npm publish to a running App Instance — and how other developers discover and build on your work.

The App Store is the package registry, deployment pipeline, and runtime host rolled into one. If you want to understand how your code is structured and executed, see Aktor Framework.

Architecture Overview​

The App Store connects four key entities:

  • AppDefinition — the immutable package stored in the registry. One entry per packageName@version. Contains the TypeScript source files, package.json metadata, and integrity hashes.
  • App Instance — a named, per-organization installation of an AppDefinition. Multiple instances of the same package can coexist with different configurations. An instance runs on the development or the production channel; see Development and Production App Instances.
  • Deployment — a configured, running instance of a single ReaktorDefinition. Each App Instance owns one Deployment per Reaktor registered by the App.
  • ReaktorDefinition — the async function your main.ts registers via registerReaktorDefinition().

Package Format​

Every App is a standard npm package. The naming convention is mandatory:

operaide-app-<name>     # must match ^operaide-app-[a-z0-9-]+$

Minimal package.json:

{
"name": "operaide-app-my-workflow",
"version": "1.0.0",
"description": "My custom workflow",
"main": "src/main.ts",
"peerDependencies": {
"@operaide/aktor": "^0.6.0"
},
"operaide": {
"label": "My Workflow",
"category": "custom",
"quality": "reference"
}
}

The peerDependencies on @operaide/aktor controls compatibility: the platform checks this semver range against its own version and blocks installation if they don't match.

The operaide field carries metadata for the App Store UI:

FieldValuesPurpose
labelfree textDisplay name in the UI; falls back to package name if unset
categoryfree text (common: core, example, demo)Grouping in the UI
qualityfree text (common: reference, showcase, experimental, template, needs-review)Signals maturity level
notesfree textShown in the details drawer

Publishing​

Two paths to get your App into the App Store:

Point your .npmrc at the Operaide registry and publish like any npm package:

# .npmrc
registry=https://your-operaide-instance/api/v1/registry
//your-operaide-instance/api/v1/registry/:_authToken=${OPERAIDE_DEPLOY_API_KEY}
npm publish

The API key must carry the NPM Registry Publisher role (or a role that implies it, such as App Developer). Keys without it get 403 Forbidden on publish. Issue a reader-only key with NPM Registry Reader for pull-only CI that runs npm install but never publishes.

The App appears in the App Store immediately after publishing.

Dependencies from external registries​

If your App depends on libraries hosted on a private npm registry (e.g. shared operaide-* libraries on another Operaide instance, a Verdaccio server, or GitHub Packages), the Operaide instance must be configured to forward requests to that upstream. This is an administrator task — see Upstream NPM Registry for the required environment variables (NPM_UPSTREAM_REGISTRY_URL, NPM_UPSTREAM_REGISTRY_AUTH_TOKEN).

As a developer, you do not need to configure .npmrc for upstream resolution. When you npm publish your App, the platform resolves dependencies from the configured upstream at install time. If a dependency cannot be found, the App installation fails with a missing-package error — ask your administrator to verify the upstream registry configuration.

Via Direct Deploy​

For faster iteration during development:

npm run deploy              # one-shot upload
npm run deploy-watch # watches for changes, re-deploys automatically

This sends your source files directly to POST /api/v1/deploy-reaktor, bypassing the npm packaging step. Useful during active development, but npm publish is the canonical distribution path.

Version Channels​

Operaide separates builds by a semver pre-release identifier on the package version:

ChannelPre-release identifierEntry pointReach
Stablenone, -rc.*, -beta.*npm publishApp Store, installable by other orgs
Dev-dev, -dev.*npm run deployYour organization only, not in registry
Builtin-builtinOperaide releaseApps shipped with the platform image

npm run deploy adds the -dev suffix automatically. Your package.json keeps its plain version like 0.6.0; the uploader patches the in-flight tarball to 0.6.0-dev before sending. The file on disk stays unchanged so npm publish keeps reading the same package.json as a stable release.

Apps bundled with the Operaide image arrive as builtin-channel versions such as 0.6.0-builtin. If you publish your own build of such an app as plain 0.6.0, your build wins: semver ranks 0.6.0 above 0.6.0-builtin, so default resolution picks your published version while the builtin one stays installable.

Mismatched channels are rejected at the API:

  • npm publish rejects any version with -dev (400). Use a plain version or a stable pre-release such as -rc.1 or -beta.2.
  • npm run deploy requires -dev. The uploader handles this; CI scripts that call POST /api/v1/deploy-reaktor directly must send a -dev version themselves.
  • The builtin identifier is reserved for the platform image. Both npm publish and npm run deploy reject it (400).

The platform UI marks dev-channel versions with a "DEV" tag and builtin versions with a "BUILT-IN" tag in the App Instances list and detail views.

Mixed-channel installs from earlier versions​

Older npm run deploy flows uploaded apps with stable version strings such as 0.6.0. After the channel split, those App Instances stay on the stable channel and run unchanged. New deploys of the same code go to the dev channel as 0.6.0-dev and create a separate App Instance lineage. To consolidate, uninstall the old stable App Instance and re-deploy.

Migration: rotate the embedded token​

Older Operaide releases baked a shared platform token into the .npmrc of every downloaded App. That token no longer authenticates against the registry, so a local App folder downloaded before this change fails npm install and npm run deploy until you replace it with a per-user key.

  1. Create a personal token: open your user profile at /profile/tokens (Tokens tab), click Create new token, set a label and expiry. Copy the value before closing the dialog. It is not shown again.

  2. Update .env: replace the OPERAIDE_DEPLOY_API_KEY value with the new token.

  3. Update .npmrc: replace the _authToken value with the same token:

    registry=https://your-operaide-instance/api/v1/registry/
    //your-operaide-instance/api/v1/registry/:_authToken="<your-token>"

Re-run npm install to confirm the registry accepts the new key, then npm run deploy to confirm the deploy endpoint accepts it.

A freshly downloaded App from the App Store already ships with both files filled in. This step is only needed for App folders downloaded before the rotation.

Code Loading and Sandbox​

When an App is installed, the platform automatically transpiles your TypeScript and runs it in an isolated sandbox. Only a fixed set of modules is available — you cannot add arbitrary npm packages beyond this list:

CategoryModules
@operaide/*aktor, ai, document, database, vector, mail
npm packagesai, axios, zod, pdf-lib, @libsql/client, fast-xml-parser, @modelcontextprotocol/sdk
Node.js builtinsnode:buffer, node:crypto, node:path, node:stream, node:url, node:util
Other operaide-*Any published operaide-* package (as library dependency)

Your registerReaktorDefinition() calls are intercepted and prefixed with the App ID to avoid naming collisions across Apps.

App Settings

You can expose configuration to the person installing your App via registerAppSettings() with a Zod schema. These settings are editable per App Instance and available at runtime through appSetting().

App Instance Lifecycle​

Installation​

From the App Store UI, clicking Deploy New Instance opens a three-step wizard:

  1. Select App — version, instance name (URL-safe, unique per org), display label and description (prefilled from package.json, both editable)
  2. App Settings — form generated from your registerAppSettings() schema
  3. Deploy — creates the App Instance and all Deployments

For scripts, CI pipelines, or agents, the same installation is available via REST:

POST /api/v2/orgs/{orgId}/apps

The request body matches the wizard fields (packageName, version, instanceName, optional label, appSettings, reaktorSettings). The full JSON Schema is retrievable via GET /api/v2/apps/schema. Both endpoints require authentication and the permToCreateReaktorInstance permission (role appManager).

Runtime​

Each Reaktor in an App Instance is exposed via REST:

GET|POST /api/v2/orgs/{orgId}/apps/{instanceName}/reaktors/{reaktorName}

App Instance status transitions: deploying → active (or error). Instances can be stopped and restarted.

Updating​

methodUpdateInstanceVersion handles version upgrades by diffing old vs. new ReaktorDefinitions: it adds new Reaktors, removes deleted ones, and updates existing Deployments in place.

Uninstalling​

Removes all Deployments, their settings, and the App Instance document. The AppDefinition in the registry remains untouched — other organizations or future installs can still use it.

Multiple Instances

You can install the same App multiple times with different names and configurations. This is useful for running the same workflow against different AI providers, datasets, or customer-facing configurations.

Core Apps vs. Custom Apps​

Every Operaide installation ships with Core Apps (op-core-*) — reference implementations like Basic Chat, Knowledge Chat, and Web Search. These are automatically published to the registry on startup from the bundled operaide-packages/ directory.

As a developer, Core Apps serve as working examples. You can start from any Core App via Create New App from Template > Develop in Operaide Studio to read the source, understand patterns, and use it as a starting point for your own Apps.

Quick Reference​

WhatWhere
App Store UILeft sidebar -> "App-Store"
App Instances list (production)Left sidebar -> "App Instances"
Development Apps list (dev)Left sidebar -> "Development Apps"
Package namingoperaide-app-<name> (lowercase, hyphens only)
Runtime API/api/v2/orgs/{orgId}/apps/{instanceName}/reaktors/{reaktorName}

For CI/tooling use:

WhatEndpoint
Publish to registryPUT /api/v1/registry/:name
Direct deployPOST /api/v1/deploy-reaktor
Create App InstancePOST /api/v2/orgs/{orgId}/apps
Instance body schemaGET /api/v2/apps/schema
Download source (Studio)GET /api/v1/download-reaktor-code/:id