Preview Packages MVP
Use this setup when a package repo already has normal build, test, and pack
checks, and you want same-repo pull requests to get installable preview
packages before merge.
The important boundary is: @async/pipeline owns the preview job, package
selection, permissions, fork policy, and comment policy; @async/release owns
preview plan, stage, and inspect evidence; async/actions/preview owns the
GitHub Packages write.
This MVP deliberately skips stable npm release publishing, main snapshots,
GitHub Release creation, Pages deploys, source-impact matrices, and release
doctor gates. Add those only when the repo needs them.
Minimum Files
Commit these files:
package.json
pnpm-lock.yaml
pipeline.ts
.github/workflows/async-pipeline.yml
.locks/pipeline/github-workflow.lock.json
Keep local run state and package artifacts out of Git:
.async/
*.tgz
.tmp/
Package Rules
sync.github.packagePreviews: true needs one public package to preview. It selects the public root package, or the single public packages/* package when the root package is private. If there are multiple public packages, set sync.github.packagePreviews.package explicitly.
For the fastest path in a private pnpm workspace:
- Keep the workspace root private.
- Pick one publishable package, such as
packages/core. - Make that package public in npm terms by removing
private: true. - Add a real package version, README or package readme, license, repository
metadata, and a files allowlist.
- Make
exportspoint at files that will exist in the package tarball. - Keep a
packtask so preview publishing proves the same tarball shape that
stable publishing will use later.
Minimal Pipeline
Create pipeline.ts at the repo root:
import { definePipeline, job, sh, task, trigger } from "@async/pipeline";
export default definePipeline({
name: "package-previews",
cache: "file:local",
sync: {
github: {
packagePreviews: true
}
},
triggers: {
pr: trigger.github({ events: ["pull_request"] }),
main: trigger.github({ events: ["push"], branches: ["main"] }),
manual: trigger.manual()
},
namedInputs: {
package: [
"src/**/*.ts",
"package.json",
"pnpm-lock.yaml",
"tsconfig.json",
"README.md",
"LICENSE"
]
},
tasks: {
test: task({
inputs: ["package"],
cache: "file:local",
run: sh`pnpm test`
}),
build: task({
dependsOn: ["test"],
inputs: ["package"],
outputs: ["dist/**"],
cache: "file:local",
run: sh`pnpm build`
}),
pack: task({
description: "Prove the package tarball is publishable before preview.",
dependsOn: ["build"],
inputs: ["package"],
cache: false,
run: sh`npm pack --dry-run --ignore-scripts`
})
},
jobs: {
verify: job({
target: "pack",
trigger: ["pr", "main", "manual"]
})
}
});
With sync.github.packagePreviews: true, sync writes a package-preview job for pull requests. The job selects the public root package or the single public packages/* package when the root is private, runs pack when present, runs @async/release preview plan, stage, and inspect evidence before publishing, then calls async/actions/preview for the selected package path.
Same-repo pull requests publish immutable 0.0.0-pr.<n>.sha.<sha> previews and can receive one install comment. Fork pull requests skip preview publishing and skip preview comments.
Nested Package Variant
When inference is ambiguous, or when only one package should preview, use object
form:
sync: {
github: {
packagePreviews: {
package: "packages/core",
target: "pack"
}
}
}
Use a nested package-aware pack task:
pack: task({
description: "Prove the package tarball is publishable before preview.",
dependsOn: ["build"],
inputs: ["package"],
cache: false,
run: sh`npm --prefix packages/core pack --dry-run --ignore-scripts`
})
GitHub Packages preview publishing uses GITHUB_TOKEN by default. If your repo
needs a different token or package namespace, configure it explicitly:
sync: {
github: {
packagePreviews: {
package: "packages/core",
target: "pack",
namespace: "scope",
tokenEnv: "PACKAGES_TOKEN"
}
}
}
Generate The Workflow
Run the local package checks:
pnpm async-pipeline run verify
Write and check the GitHub workflow:
pnpm async-pipeline sync github generate
pnpm async-pipeline sync github check
Inspect the preview job without publishing:
pnpm async-pipeline github plan --job package-preview --event pull_request --format json
pnpm async-pipeline github run --job package-preview --event pull_request --mock-network
Commit the workflow and lock:
.github/workflows/async-pipeline.yml
.locks/pipeline/github-workflow.lock.json
Pull Request Procedure
- Open or update a non-draft same-repo pull request.
- Let the
package-previewjob run after the normal verify path. - Install the preview from the comment or from the GitHub Packages tag.
- Treat fork pull requests as verify-only unless a maintainer moves the change
into a trusted branch.
For stable npm publishing, add the npm release MVP or the combined package repo
MVP instead of adding ad hoc publish shell to the preview job.