This document covers how Output packages are versioned, built, and published to npm.
This monorepo publishes the following packages to npm:
| Package | Path | Description |
|---|---|---|
@outputai/cli |
sdk/cli |
CLI for project scaffolding and workflow management |
@outputai/core |
sdk/core |
Core framework (workflows, steps, parallel execution) |
@outputai/llm |
sdk/llm |
LLM integration (generateText, prompt loading) |
@outputai/http |
sdk/http |
HTTP client with tracing |
@outputai/evals |
sdk/evals |
Evaluation framework (LLM-as-judge) |
@outputai/credentials |
sdk/credentials |
Encrypted credential management |
@outputai/output |
sdk/framework |
Umbrella package (re-exports all SDK packages) |
output-api |
api |
API server (private, Docker image only) |
All @outputai/* packages and output-api are in a fixed version group — they always share the same version number and are bumped together. This is configured in .changeset/config.json.
There are three ways packages get published, each tied to a dist tag on npm:
┌──────────────────────────────┐
You merge a PR │ push to main triggers two │
─────────────────────► │ workflows in parallel: │
│ │
│ 1. release.yml │
│ → opens "Version │
│ Packages" PR │
│ (if changesets exist) │
│ │
│ 2. publish_next.yml │
│ → publishes @next │
│ immediately │
└──────────────────────────────┘
You merge the publish.yml
"Version Packages" PR ───► → publishes @latest
→ API image + git tags
You click "Run workflow" publish_dev.yml
in GitHub Actions ───► → publishes @dev
(any branch/SHA)
| Tag | Version example | Install | When it publishes |
|---|---|---|---|
latest |
0.1.4 |
npx @outputai/cli |
When you merge the "Version Packages" PR |
next |
0.1.4-next.abc1234 |
npx @outputai/cli@next |
Automatically on every push to main |
dev |
0.1.4-dev.0 |
npx @outputai/cli@dev |
Manually from GitHub Actions (any branch) |
All dist tags apply to every published package, not just the CLI.
Changesets is a tool that manages version bumps and changelogs for monorepos. Instead of manually editing package.json versions, you describe what changed and let the tooling handle the rest.
A changeset is a small markdown file that lives in .changeset/ and describes:
- Which packages are affected
- What kind of bump (patch, minor, major)
- A description of the change
Here's a real example from this repo (.changeset/fix-publish-add-next.md):
---
"@outputai/cli": patch
---
Fix prod publish to include build step before publishing to npm.The frontmatter (--- block) says "bump @outputai/cli by a patch version." Since all our packages are in a fixed group, this actually bumps all of them together.
| Change type | Changeset needed? |
|---|---|
| New feature, bug fix, breaking change | Yes |
| Dependency update that affects behavior | Yes |
| CI/CD changes, docs-only, internal refactors | No |
| Claude plugin updates | No |
If unsure, ask: "Would a user installing our packages notice this change?" If yes, add a changeset.
This is the full lifecycle of a stable release:
While working on your feature branch, run:
pnpm changesetThe CLI will ask you:
- Which packages changed? (select with space, confirm with enter)
- Is it a major, minor, or patch bump?
- Write a summary of the change
This creates a file like .changeset/cool-dogs-jump.md (random name). Commit it with your PR.
You can also create the file by hand — it's just markdown with YAML frontmatter.
Nothing special here. Just merge as usual. Two things happen automatically:
-
@nextpublishes immediately — your change is available via@outputai/cli@nextwithin minutes. -
The Release workflow (
release.yml) looks for.changeset/*.mdfiles and opens (or updates) a PR titled "Version Packages". That PR:- Deletes the changeset files
- Bumps
versionin everypackage.json - Updates
CHANGELOG.mdin each package - Syncs the CLI's embedded SDK version
You don't need to merge this immediately. Multiple PRs with changesets can accumulate — the "Version Packages" PR will keep updating itself.
When you're ready to cut a stable release, merge the "Version Packages" PR so main contains the bumped versions and changelogs. That merge starts the Publish workflow (publish.yml), which executes:
ops/publish_npm.sh— install dependencies, build packages, and publish to npm under@latestops/publish_api.sh— build and push the API Docker image (semver tags and:lateston the registry)ops/tag.sh— create and push the release git tag (for examplev0.1.4)
If you need the same steps without a new merge, you can run that workflow again from the Actions tab (workflow_dispatch).
That's it. Users running npx @outputai/cli will now get the new version.
Every push to main triggers publish_next.yml automatically — no changeset needed. Each run will execute:
ops/bump_prerelease.sh— bump all packages to a prerelease tied to the commit SHA (for example0.1.4-next.abc1234)ops/publish_npm.sh— publish npm packages under thenextdist-tagops/publish_api.sh— build and push the API image without updating the Dockerlatestaliases
We rely on CI having passed on the PR before merge, so this workflow does not run the full ops/validate.sh gate again. For more detail on any script, see ops/README.md.
This means every merged PR is immediately available:
npx @outputai/cli@next init my-projectUseful for:
- Testing changes before a stable release
- CI/CD pipelines that want to track main
- Early adopters who want the latest
publish_dev.yml is triggered manually from GitHub Actions. You can publish from any branch or SHA.
- Go to Actions > "Publish Dev" > "Run workflow"
- Optionally enter a branch name or commit SHA (defaults to
main) - Packages are published with a
-dev.Nprerelease suffix under thedevdist-tag
Each run then executes:
ops/validate.sh— full validation before publishops/bump_prerelease.sh— bump thedevprerelease lineops/publish_npm.sh— publish npm packages under thedevdist-tagops/publish_api.sh— build and push the API image without Docker alias tags
See ops/README.md for what each script does and when to be careful.
npx @outputai/cli@dev init my-projectUseful for:
- Testing a feature branch before merging
- Sharing a WIP build with someone for review
All publish paths run pnpm -r run build before publishing. This compiles TypeScript to dist/ in each package. Without the build step, published packages will be missing compiled code.
The build order is managed by pnpm workspace dependencies — packages are built in dependency order automatically.
See ops/README.md for what each script under ops/ is for and important caveats.
The build step was not run before publish.
Clear the npx cache and retry:
npx --yes @outputai/cli@latest init my-projectMake sure your changeset files are committed to main. The Release workflow only runs on push to main.
That's expected. Merging your PR only publishes to @next. The @latest tag only updates when you merge the "Version Packages" PR. If no "Version Packages" PR exists, your PR probably didn't include a changeset.