Skip to main content

Publishing

I publish the platform packages as restricted-access packages to the npm registry under the @opentabs-dev org. The process is mostly automated, but there are enough moving parts that I wrote it all down. Here's the full workflow.

Packages

Seven platform packages are published. The dependency order matters — get it wrong and downstream packages reference versions that don't exist yet:

OrderPackageDepends on
1@opentabs-dev/shared
2@opentabs-dev/browser-extensionshared
3@opentabs-dev/mcp-servershared
4@opentabs-dev/plugin-sdkshared
5@opentabs-dev/plugin-toolsplugin-sdk, shared
6@opentabs-dev/climcp-server, browser-extension, plugin-sdk, plugin-tools, shared
7@opentabs-dev/create-plugincli

All seven packages are published to npm. browser-extension and mcp-server are additionally bundled with the CLI — opentabs start uses the bundled MCP server and auto-installs the bundled browser extension to ~/.opentabs/extension/.

npm Authentication (One-Time Setup)

Create a granular access token at npmjs.com/settings/tokens/create:

  • Permissions: Read and Write
  • Packages: @opentabs-dev/*
  • Bypass 2FA: Enabled

Save the token to ~/.npmrc:

echo '//registry.npmjs.org/:_authToken=<YOUR_TOKEN>' > ~/.npmrc

Verify it works:

npm whoami

Publishing a Release

I automated the entire publish workflow in a single script. It handles everything in one shot:

npx tsx scripts/publish.ts 0.0.17

The script:

  1. Verifies npm authentication via npm whoami
  2. Bumps "version" in all seven platform/*/package.json files
  3. Deletes the lockfile, runs npm install, and runs npm run build:force to sync lockfile and rebuild with the new versions
  4. Publishes in dependency order: sharedbrowser-extensionmcp-serverplugin-sdkplugin-toolsclicreate-plugin
  5. Updates plugin @opentabs-dev/* dependencies to ^version and rebuilds each plugin
  6. Generates a changelog from git log since the previous tag
  7. Creates a release commit and tag (v<version>)

Six packages use "publishConfig": { "access": "restricted" } explicitly. browser-extension omits publishConfig but is still restricted — npm defaults to restricted access for scoped packages. Only authenticated npm users with access to the @opentabs-dev scope can install them.

After Publishing

After a release, every plugin that depends on @opentabs-dev/* packages needs its dependencies updated. This is the tedious part:

cd plugins/slack
# Update @opentabs-dev/* versions in package.json
npm install
npm run build

The opentabs-plugin build command embeds the installed SDK version as sdkVersion in dist/tools.json. The MCP server checks this at discovery time — if a plugin was built with a newer SDK than the server, it is rejected with a clear rebuild message.

Version Compatibility

The MCP server checks that plugins weren't built with a newer SDK than it understands. It uses major.minor comparison:

  • A plugin's major.minor must be less than or equal to the server's major.minor
  • Patch differences are always fine
  • Plugins without sdkVersion in tools.json (predating this feature) load with a warning

In practice, this means patch releases are painless — existing plugins keep working without rebuilding. A minor or major bump (e.g., 0.0.x0.1.0) requires plugins to rebuild with the new SDK.

What NOT to Publish

  • plugins/* — example plugins are standalone projects that publish independently to npm under opentabs-plugin-* names

Last Updated: 10 Mar, 2026