Package Repo MVP
Use this setup when a package repo needs the three common public surfaces:
stable npm releases, pull request preview packages, and GitHub Pages docs.
The important boundary is: pipeline.ts owns the local task graph and the
GitHub job policy; @async/release owns package-aware release and preview
evidence; async/actions owns the networked npm, GitHub Packages, comment, and
Pages steps.
This MVP assumes one package is being released first. For a private workspace
root, keep the root private and choose one package path under packages/*.
After this works, repeat the package path pattern or graduate to a fuller
multi-package release plan.
Minimum Files
Commit these files:
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
pipeline.ts
README.md
LICENSE
CHANGELOG.md
.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 Setup
Make the first package release-ready before adding release jobs:
- Remove
private: truefrom the package that should publish. - Set the npm version you intend to publish.
- Add license, repository, README or package readme, and package-specific
keywords.
- Make
exportspoint at files that belong in the npm tarball. - Add a
filesallowlist fordist/, package metadata, README, and license. - Keep unreleased implementation packages private.
- Keep workspace dependencies as
workspace:*until your release process
deliberately publishes or rewrites them in order.
Configure npm trusted publishing for the committed workflow file, the publish
job, and the npm-publish environment. If the repo still uses token auth, wire
NODE_AUTH_TOKEN to an npm token secret as shown in the npm release MVP.
Configure the repository's Pages source to GitHub Actions before relying on
Pages deploys.
Minimal Pipeline
Create pipeline.ts at the repo root. This example publishes
packages/core, publishes PR previews for that package, and deploys static docs
from .async/pages.
import { definePipeline, job, sh, task, trigger } from "@async/pipeline";
const packageName = "@scope/core";
export default definePipeline({
name: "package-repo",
cache: "file:local",
sync: {
github: {
packagePreviews: {
package: "packages/core",
target: "pack"
},
pages: {
target: "docs.site",
build: { kind: "static", path: ".async/pages" }
},
evidence: true
}
},
triggers: {
pr: trigger.github({ events: ["pull_request"] }),
main: trigger.github({ events: ["push"], branches: ["main"] }),
manual: trigger.manual()
},
namedInputs: {
package: [
"packages/core/src/**/*.ts",
"packages/core/package.json",
"package.json",
"pnpm-lock.yaml",
"pnpm-workspace.yaml",
"tsconfig.json",
"README.md",
"LICENSE",
"CHANGELOG.md"
],
docs: [
"docs/**",
"README.md",
"packages/core/src/**/*.ts",
"packages/core/package.json",
"package.json",
"pnpm-lock.yaml"
]
},
tasks: {
test: task({
inputs: ["package"],
cache: "file:local",
run: sh`pnpm test`
}),
build: task({
dependsOn: ["test"],
inputs: ["package"],
outputs: ["packages/core/dist/**"],
cache: "file:local",
run: sh`pnpm build`
}),
pack: task({
description: "Prove the package tarball is publishable.",
dependsOn: ["build"],
inputs: ["package"],
cache: false,
run: sh`npm --prefix packages/core pack --dry-run --ignore-scripts`
}),
"docs.site": task({
description: "Build the static GitHub Pages artifact.",
dependsOn: ["build"],
inputs: ["docs"],
outputs: [".async/pages/**"],
cache: false,
run: sh`pnpm docs:build`
}),
"release.ensure": task({
description: "Create or verify the GitHub Release for the package version.",
dependsOn: ["pack"],
inputs: ["package"],
cache: false,
run: sh`pnpm async-pipeline release ensure --package packages/core`
}),
publish: task({
description: "Publish the current package version to npm.",
dependsOn: ["release.ensure"],
inputs: ["package"],
cache: false,
run: sh`pnpm async-pipeline publish npm --package packages/core`
})
},
jobs: {
verify: job({
target: "pack",
trigger: ["pr", "main"]
}),
publish: job({
target: "publish",
trigger: ["manual"],
environment: {
name: "npm-publish",
url: `https://www.npmjs.com/package/${packageName}`
},
requires: {
provenance: true
}
})
}
});
This combined MVP has four workflow lanes:
verifyruns test, build, and pack on pull requests andmain.package-previewruns on pull requests, uses the samepacktarget, runs@async/releasepreview evidence, publishes trusted same-repo PR previews to GitHub Packages, and skips forks.pagesbuilds the static Pages artifact on pull requests and deploys it frommainor selected manual dispatch.publishis manual and runsrelease ensurebefore the npm publish command.
release ensure creates or verifies the v<version> Git tag and GitHub Release for the package version. The exact publish npm command is lowered into Async publish action steps, with @async/release evidence before npm publishing.
Root Package Variant
For a repo whose root package is the package being released, use . instead of
packages/core:
sync: {
github: {
packagePreviews: true,
pages: { target: "docs.site" },
evidence: true
}
}
pack: task({
dependsOn: ["build"],
inputs: ["package"],
cache: false,
run: sh`npm pack --dry-run --ignore-scripts`
}),
"release.ensure": task({
dependsOn: ["pack"],
inputs: ["package"],
cache: false,
run: sh`pnpm async-pipeline release ensure --package .`
}),
publish: task({
dependsOn: ["release.ensure"],
inputs: ["package"],
cache: false,
run: sh`pnpm async-pipeline publish npm --package .`
})
Generate The Workflow
Run the package and docs checks locally:
pnpm async-pipeline run verify
pnpm async-pipeline run-task docs.site
Write and check the GitHub workflow:
pnpm async-pipeline sync github generate
pnpm async-pipeline sync github check
Inspect the networked jobs without publishing or deploying:
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
pnpm async-pipeline github plan --job pages --event pull_request --format json
pnpm async-pipeline github run --job pages --event pull_request --mock-network
pnpm async-pipeline github plan --job publish --event workflow_dispatch --selected-job publish --format json
pnpm async-pipeline github run --job publish --event workflow_dispatch --dry-run
Commit the workflow and lock:
.github/workflows/async-pipeline.yml
.locks/pipeline/github-workflow.lock.json
Daily Procedure
Pull request:
- Run or wait for
verify. - Use the
package-previewinstall comment for same-repo PRs. - Check the Pages build artifact through the
pagesjob.
Main branch:
- Merge only after
verifypasses. - Let the
pagesdeploy job publish docs frommain.
Stable release:
- Update the package version and
CHANGELOG.md. - Merge the verified release commit.
- Dispatch the
publishjob. - Confirm the package version is visible on npm and the GitHub Release matches
the changelog section.
Use the narrower npm release, preview packages, or GitHub Pages MVP docs when
the repo needs only one surface.