A release agent can turn a dozen Conventional Commits into a version, changelog, and npm tarball without a maintainer touching the keyboard. If it also holds the npm token, one mistaken version or compromised dependency can move from a plausible summary to a public release in the same run.
The useful design question is not whether to “keep a human in the loop.” It is which exact transition needs a person, and what evidence they need before approving it. Let the agent do reversible work and assemble a candidate; put the gate immediately before an action that changes shared state, spends authority, or is difficult to undo.
Put the pause before the irreversible action
Think of an agent’s work as a sequence of permissions, not a single task. Reading commits, drafting release notes, and running tests are different from publishing a package or changing a production deployment. A blanket approval at the start blocks harmless preparation; an approval after publication is just an incident notification.
This distinction matters because two trends meet in developer automation. Agents are increasingly framed as a way to supervise repetitive work rather than perform every step manually, while CI/CD workflows already automate versioning, tests, and release operations. But a pipeline’s ability to automate a step does not mean the step should inherit an agent’s broad authority.
Use this rule: automate preparation when errors are detectable and cheap to reverse; require approval before an action affects users, shared infrastructure, or an external system. The gate belongs at the boundary between a candidate and a consequence.
Use an npm release to locate the boundary
Suppose an agent handles a release chore for a package using Conventional Commits. It reads commits since the last release, proposes a SemVer bump, writes release notes, runs the test suite, and creates a package tarball. Those steps produce a reviewable candidate; none has to publish anything.
The agent can also flag uncertainty: a commit message that does not follow the team’s convention, a failing test, or a package version that looks inconsistent with the proposed change. That is useful preparation, not a reason to grant it a token that can publish to npm.
The critical transition is npm publish. Once the package is public, consumers may install it and downstream automation may act on it. A later deprecation or corrective release cannot make every installation disappear. So the human review belongs after the candidate is built and checked, but before publication credentials are used.
Decide by consequence, not by how clever the agent sounds
A polished explanation is not evidence that a high-impact action is safe. Apply the same boundary whether the candidate was assembled by a language model, a script, or a conventional release tool such as semantic-release, which automates versioning, release notes, and publishing.
| Workflow step | Agent may prepare | Human checkpoint |
|---|---|---|
| Inspect commits | Group changes and suggest a SemVer bump | Review ambiguous or breaking changes |
| Draft release notes | Summarize commits for users | Correct misleading claims or omissions |
| Build candidate | Run tests and create a tarball | Check failures or unexpected files |
| Publish package | Prepare the publish command | Approve the exact candidate before credentials are used |
| Announce release | Draft a post or notification | Approve messages sent to customers or public channels |
For a small internal tool, a version bump may be easy to reverse. For a public library, a bad release can affect other teams’ builds. Keep the decision tied to the consequence and exposure of the particular package, not a universal rule that every agent action needs approval.
Make the candidate reviewable before asking for approval
An approval request should point to one specific artifact, not a vague instruction to “review the release.” Include the proposed version, commit range, test result, tarball name, checksum, and any warnings. The reviewer should be able to compare what the agent recommends with what will actually be published.
GitHub Actions can write a candidate summary to the workflow run’s summary page using GITHUB_STEP_SUMMARY. That makes the information concrete and attached to the run. However, do not assume GitHub’s environment approval screen displays that custom summary: treat the environment gate as an enforcement control, and direct the reviewer to the run summary or a linked pull request for the evidence.
Keep the approval tied to the same run and artifact. If someone rebuilds the package after review, the old approval should not authorize the new bytes. A checksum helps identify the reviewed file, though it does not prove that the file itself is trustworthy.
Separate preparation from publishing in GitHub Actions
The following workflow outline builds a tarball in one job and puts the publish job behind a GitHub Actions environment named npm-production. Configure that environment in repository settings with required reviewers. The preparation job does not receive the npm token; the publish job gets it only after the environment gate is approved.
jobs:
prepare:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm test
- run: |
mkdir -p dist
npm pack --pack-destination dist
cd dist
sha256sum *.tgz > SHA256SUMS
- name: Write candidate summary
run: |
echo "## Release candidate" >> "$GITHUB_STEP_SUMMARY"
echo "- Revision: \`$GITHUB_SHA\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Package: \`$(node -p "require('./package.json').name")\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Version: \`$(node -p "require('./package.json').version")\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Tarball and SHA256SUMS are in the release-candidate artifact." >> "$GITHUB_STEP_SUMMARY"
echo "- Warnings: none reported by this workflow." >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
with:
name: release-candidate
path: dist/
publish:
needs: prepare
runs-on: ubuntu-latest
environment: npm-production
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: release-candidate
path: dist
- name: Verify candidate
run: cd dist && sha256sum -c SHA256SUMS
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish dist/*.tgz
The checksum commands intentionally run in dist: the preparation job writes dist/SHA256SUMS with filenames relative to that directory, and the publish job verifies the manifest from the same directory. A checksum catches accidental changes between creation and verification, but because the tarball and manifest travel together, it is not an independent signature or proof that an agent-created package is safe.
Know what the approval screen does—and does not—show
Before enabling this workflow, run it once without a real publish token and inspect the approval experience. In the Actions run, open the prepare job’s summary to see the candidate details; inspect the uploaded artifact if you need to verify its contents. The environment approval is the gate that blocks the dependent job, not a substitute for presenting all those details in the approval prompt.
Give reviewers a direct route to the run. For a team that requires a richer review record, open a pull request containing the proposed release notes and version, and link it to the workflow run. The human can review the PR and run summary before approving the environment. If that feels too cumbersome for routine patch releases, make the review lighter—but do not silently move the approval to after publishing.
Also decide who can approve. A gate that any workflow contributor can satisfy may not provide meaningful separation of duties. Match the reviewer list to the package’s impact and the organization’s release policy.
Configure npm authentication only in the gated job
Setting NODE_AUTH_TOKEN alone does not tell npm which registry to authenticate against. Add an .npmrc file at the repository root, beside package.json, with registry configuration such as:
registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
Commit this file without a real token. In the publish job, provide the token as the NODE_AUTH_TOKEN environment variable, as shown above, and keep the secret out of the preparation job. For a scoped package or a different registry, configure the appropriate registry and scope in the project’s .npmrc; do not assume the public npm registry setting applies to every package.
This split limits exposure: tests and package generation can run without publication credentials, and the token becomes available only in the job protected by the environment. It does not eliminate every supply-chain risk. A compromised dependency can still affect a build, so retain ordinary checks and review the actual package contents when the release warrants it.
Start with one gate and tune it this week
Do not begin by asking an agent to own your entire release pipeline. Pick one repetitive chore—such as preparing release notes and an npm tarball—and separate it into preparation, verification, and publication. Then decide whether each action is reversible, who can see its output, and which credential it requires.
- Have the agent prepare a candidate without publishing credentials.
- Show the version, commit range, test outcome, tarball, checksum, and warnings in a workflow summary or reviewable pull request.
- Put a required human approval on the job that performs the external action.
- Test the gate with a harmless run, then confirm the exact artifact reviewed is the one the publish job uses.
After a few releases, use real friction as your signal: if reviewers repeatedly approve clean patch candidates, improve the summary or narrow the gate rather than removing review blindly. If a warning is often missed, make it a blocking check. The goal is not maximum human involvement; it is to spend human attention at the point where a mistake becomes someone else’s problem.