GitHub Releases is the
canonical changelog. Under the current process, each new release combines a
short, reviewed summary with a categorized list of merged pull requests.
Historical releases may contain generated notes only. The release tag and npm
package use the same stable version: npm-vX.Y.Z and
@openai/codex-security@X.Y.Z. Releases whose source includes the GitHub Action
also publish action-vX.Y.Z, which installs that exact CLI version. The Action's
manifest and SBOM accompany the npm archive on the same GitHub Release.
Pull request titles must follow this form:
<type>[optional scope][!]: <description>
Use a lowercase type beginning with a letter and containing only letters, digits, and hyphens. Use a lowercase scope when present. Start the description with a non-whitespace character and do not leave trailing whitespace. Examples:
feat(cli): add component scan planning
fix(windows): preserve Unicode paths
docs: explain scan cost limits
feat(sdk)!: remove the legacy result field
The title controls the generated release category:
| Title | Release category |
|---|---|
Any type with ! |
Breaking changes |
feat |
Features |
fix |
Fixes |
docs |
Documentation |
chore(release), release, test |
Excluded |
| Any other type | Other changes |
Use chore(release) for release preparation and test for test-only changes.
The legacy release type remains supported. Use these only for changes that
do not affect package users. A maintainer can apply skip-release-notes to
exclude another internal change. That manual label takes precedence over the
title category.
Dependabot checks npm packages, Python test dependencies, and GitHub Actions daily, including weekends. OpenAI dependencies have no release cooldown; other releases must be at least seven days old. Security updates do not wait for the version-update cooldown. Updates still require review and passing CI; nothing is merged automatically.
Keep @openai/codex and @openai/codex-sdk on the same exact version across the
TypeScript SDK, MCP app, and triage evals in evals/triage-finding. Dependabot
groups their updates across all three projects, and the SDK tests reject
mismatched pins or multiple locked SDK versions. The evals override Promptfoo's
transitive Codex SDK to the direct SDK dependency so it follows the same update.
Each pnpm project applies the same seven-day age policy to newly resolved
dependencies, including transitive packages, with openai and @openai/* exempt.
Committed lockfiles remain installable. The existing Socket release checks remain
in place.
The production dependency audit is a blocking step in CI package builds and npm
release validation. pnpm --dir sdk/typescript run audit:prod checks the locked
production graph at the existing high-severity threshold. High or critical
advisories and audit service failures stop publication. Resolve dependency
advisories with dependency and lockfile updates; retry service failures once
the audit service is available.
While the package is on 0.x, ordinary changes, including features, use a
patch release. Breaking changes use a minor release and reset the patch to
zero. For example, changes after 0.1.23 propose 0.1.24, or 0.2.0 if any
included change is breaking. The category of a feature remains Features;
the category does not imply a minor version bump.
The release PR updater recognizes breaking changes from a ! in a
Conventional Commit title, a BREAKING CHANGE: or BREAKING-CHANGE: footer,
or the breaking-change label. skip-release-notes affects visibility, not
version impact. All merges and direct commits after the release boundary
count toward the next version, including documentation and internal changes.
Review this policy before enabling automation for 1.x.
node-release-pr runs after pushes to main and can be dispatched manually.
It defaults to a read-only preview. It does not merge, tag, publish, or change
the existing publication gates.
The updater opens one ready-for-review proposal on release/next-<base-version>
once a change reaches main after the current package version. It recomputes
the proposal's version from all changes since that package version first
reached main. Squash-merge release PRs, as required by this
repository's enabled merge method, so the whole proposal lands as one
release boundary commit. Generated PR titles and commit subjects use
chore(release): X.Y.Z, matching the proposed package version. Confirm the
squash commit subject uses the current PR title when merging. A later breaking
change updates the version and title on the same PR. Each update incorporates
the latest main and appends a commit; the updater never force-pushes.
A concurrent commit causes it to reread and
retry. It requests Codex review when the proposal files change. Updates that
only incorporate main keep CI current without repeating the same proposal
review. New suggestions for human-owned notes still appear in a comment.
Before merging the proposal, check CI and request a final Codex review
if the last review targets an older head.
The proposal updates the SDK version and the Action version in
github-action/package.json and github-action/package-lock.json together.
The Action's runtime dependency and lockfile keep their previously published
CLI version until npm publishes the proposed version. Release packaging then
updates that pin and lockfile to the verified publication. This lets release
PRs run CI while the next npm version is still unavailable; node-ci also
tests the Action against the packed CLI candidate before publication.
If a run reports that GitHub has not exposed the updated PR head, manually rerun the updater with dry_run disabled after the PR catches up. This allows any deferred review request or note suggestions to be posted. Verify review on the current head before merging the proposal.
When the release version merges, the updater waits for another change to
reach main before opening the next proposal. An empty release cycle returns
action: "unchanged" without creating a branch or PR. Publication of the
previous version still has to complete and pass the verification steps below.
The updater leaves another open chore(release): or legacy release: PR
targeting main, including a manually prepared release, untouched and does not
open a duplicate. Finish or close that PR before enabling the new flow.
Closing an automated proposal
pauses its cycle; reopen it to resume. Retargeting it away from main also
pauses updates; restore its main base before resuming. Both ready proposals
and existing drafts receive updates. Existing drafts can be marked ready
without pausing the updater. Review the current head before merging if
main has advanced. The updater rechecks pause conditions before advancing
the branch. Changes to other files on the release branch, or to package
fields other than the version, also pause the
updater so those edits cannot be lost. These intentional pauses return
action: "held" and leave the workflow successful. Preserve or merge the
additional changes, then rerun the updater to resume.
The committed .github/release-notes.md is authoritative. The updater
drafts highlights from merged titles and lists marked breaking changes for
migration review; it does not infer migration instructions from source code.
Review and refine these suggestions before releasing.
- Edit the highlights or upgrade notes on the release PR branch. Keep the
surrounding
release-sectioncomments if you want to retain section boundaries. The bot refreshes a section only while it matches the last generated draft. An edit or deletion makes that section human-owned, and later updates preserve it. Custom prose outside the sections is preserved. - Later suggestions appear in a new bot comment on the same PR. They do not replace human-owned notes. The bot updates the version header and PR title but never rewrites the PR description. Review version-specific links in human-owned prose when the proposed version changes.
.github/release-pr-state.jsonrecords the cycle and section ownership. To explicitly regenerate a section, add"reset": trueto that section's state entry. The next run consumes the reset and resumes automatic updates. Restore any damaged section markers before resetting. Do not delete the state file to reset ownership. A section with missing ownership metadata is preserved until explicitly reset; missing state does not authorize replacing manual notes.- Deleting the notes file is preserved too. Restore reviewed notes, or explicitly reset the sections, before merging; publication requires the versioned notes file.
With an authenticated gh CLI, a local checkout can preview the plan with:
RELEASE_PR_DRY_RUN=true node sdk/typescript/scripts/release-pr.mjsThe preview may fetch missing Git objects locally, but performs no GitHub
writes. Its JSON output includes the proposed files and any reason the
updater would pause. After the workflow is on main, use its Run workflow
form with dry_run enabled to test the hosted read-only path.
To test writes, enable Allow GitHub Actions to create and approve pull requests
under the repository's Settings → Actions → General → Workflow permissions,
then manually dispatch the workflow with dry_run disabled. This permits a
single write run while automatic updates remain disabled. The workflow uses
the repository's GITHUB_TOKEN with Contents: write and Pull requests: write
by default; no separate App credentials are required. Preview runs use a separate
job with read-only permissions for both scopes.
Review the resulting PR and select Approve workflows to run in its merge
box to start hosted CI. GitHub requires this approval for PRs created or updated
with GITHUB_TOKEN. Check the Codex review on the current head as well, and
request it manually if the automated request has not started a review.
For CI to start without this approval, optionally configure a GitHub App
installed on this repository with Contents: write and Pull requests: write.
Set the RELEASE_APP_CLIENT_ID repository variable and RELEASE_APP_PRIVATE_KEY
secret. When the Client ID is configured, write runs request an App token scoped
to this repository; a missing or invalid private key fails the run. Previews
always use GITHUB_TOKEN. See GitHub's token documentation.
After the manual write run is verified, set the RELEASE_PR_ENABLED
repository variable to true to allow updates after pushes to main.
Remove it or set it to false to return push-triggered runs to previews.
Manual runs always honor their dry_run input, which defaults to a preview;
disabling automatic updates does not prevent an explicit manual write run.
Generated PRs leave the disclosure attestations unchecked for maintainer review.
- Choose the next stable version and update
sdk/typescript/package.json,github-action/package.json, and both root version fields ingithub-action/package-lock.json. The rolling release PR normally prepares these changes. Keep the Action runtime pin on the previously published CLI; release packaging updates it after npm publication. - Update
.github/release-notes.md. Its first line must be<!-- release-version: X.Y.Z -->with the exact package version. - Summarize the changes a user will notice. Call out required migration or compatibility work, link relevant public documentation, and leave the pull-request inventory to the generated section.
- Open a pull request with a strict Conventional Commit title such as
chore(release): 0.2.0. - Run the checks required by the changed files and record the results in the pull request. Do not merge until required CI, review, and public disclosure checks pass on the current commit.
Review the summary with the same standard as product documentation. Keep it specific, describe behavior before implementation, and do not include private repositories, systems, people, findings, links, or issue identifiers.
The release starts after the version bump reaches main and node-ci succeeds
for that exact commit:
node-release-cutverifies that the version increased, checks the reviewed summary, and creates the exactnpm-vX.Y.Ztag.node-releaseinstalls the committed dependency graph, tests and packs the package, publishes it to npm, and records npm provenance.node-github-releaseverifies the public package, provenance, tag, and archive before publishing the GitHub release. It prepends the reviewed summary to GitHub's categorized notes.- The same workflow runs
published-install-smokeagainst the exact published version on Linux, macOS, and Windows. It uses the current release automation so the checks also work for historical backfills. - If the release source contains
action.yml, the workflow prepares the Action from that exact source commit, pins its runtime to the verified npm version and integrity, and fetches the locked runtime through Socket Firewall with an empty cache before executing it. The lock retains public npm URLs. It builds and tests the distribution in a job with read-only repository permissions. A fresh publisher checks out the same source, downloads only the tested runtime lock by artifact ID, and rebuilds and verifies the bundles without executing the CLI. It createsaction-vX.Y.Zand uploads the Action release manifest and SBOM to the existingnpm-vX.Y.ZGitHub Release. A final status job reports publication, installation smoke, and Action results.
The Action tag points to a generated distribution commit whose parent is the CLI release commit. That additional commit contains the runnable Action bundle and runtime lockfile. Its release manifest records both commits, both tags, the aligned version, and the npm integrity. Metadata finalization verifies the bundle hashes against the files being published. Consumers can pin the Action's distribution commit from that manifest.
Historical releases whose source predates action.yml skip Action publication
and still run the exact-version installation checks. The workflow does not add
Action code from a later commit to an older CLI release.
After npm accepts a publication, its registry can take several minutes to expose the version. GitHub publication waits up to ten minutes for that version to become available before verifying its archive and signed provenance. Other registry errors fail immediately.
node-release generates the npm plugin payload from the canonical source under
plugins/codex-security/ during prepack. The generated
sdk/typescript/_bundled_plugin/ directory is not a committed release input;
do not prepare a release by editing or committing files there.
Monitor all three workflows and the final status in node-github-release.
A release is complete when npm and GitHub publication, exact-version install
checks, and applicable Action publication have succeeded. The protected npm
publication gates and immutable npm-vX.Y.Z tag remain in place.
Container publication currently has its own workflow and approval. It uses
container-vX.Y.Z or a manual container-release run on main, with the version
matching the SDK package. It is not part of the coordinated npm and Action
completion status. See Container releases for its
publication and verification steps.
Check the published state before announcing the release:
npm-vX.Y.Zpoints to the merged release commit.npm view @openai/codex-security@X.Y.Zreports the expected version and commit, and the provenance check passed innode-release.- The GitHub release is stable, has the correct title, and contains one verified npm package archive plus the Action manifest and SBOM when applicable.
- The exact-version published installation checks succeeded.
- For releases with the Action,
action-vX.Y.Zpoints to the distribution commit recorded in its manifest, whose parent is the CLI release commit. The manifest and runtime lock identify the same CLI version and npm integrity. - The newest version is marked Latest. A historical backfill is not.
- For releases created under this process, the reviewed highlights, category headings, documentation links, and full comparison link are correct. Historical releases may have generated notes only.
- Every merged pull request is included or has an intentional
skip-release-noteslabel.
The published-install-smoke workflow checks each exact version during release
publication. It also checks npm's current latest daily and on pull requests
changing its smoke checks. Manual dispatch accepts a version (default
latest) and an optional ref for the source of the smoke checks. It installs
into a temporary consumer, verifies the requested version, checks the npm CLI
shim and public SDK, starts the bundled Codex executable with --version,
and initializes the bundled MCP server. Linux covers supported Node majors
22, 24, and 26; macOS and Windows cover Node 24. These checks use temporary
configuration directories and do not run scans or call model APIs.
The smoke test verifies the installed package independently of the version on
main, so it can run while the checkout contains unreleased changes. A failure
reports the installed version or failing startup command in the Actions log;
inspect that job before treating it as a release regression. To reproduce
locally, run node sdk/typescript/scripts/smoke-published-package.mjs X.Y.Z
from the repository. Omit the version to check latest.
Do not retarget a release tag or publish a second package under the same version. The workflows are designed to recover from partial publication while keeping the original tag and package identity.
To retry GitHub publication, run node-github-release from main with the
existing npm-vX.Y.Z tag. Supply the successful node-release run ID when
automatic lookup is not enough. The workflow verifies the npm artifact and
provenance again before it creates or updates the release, repeats the
exact-version installation checks, and completes applicable Action publication.
If action-vX.Y.Z already exists, recovery checks its package manifests and
lockfiles against the reviewed source and CLI release identity before installing
dependencies or running package scripts. It then reuses that distribution commit.
Do not move that tag or regenerate the release from newer Action source.
A failure after npm publication can leave
the npm package or GitHub Release visible while later checks or Action
publication remain incomplete; use the final workflow status to identify the
remaining work.
To repair categories on an existing release, correct the merged pull request's
title or release label first, then rerun node-github-release for the tag. For
a release that predates .github/release-notes.md, start the existing release
body with this marker block. Keep a blank line between the end marker and the
generated notes:
<!-- codex-security-release-summary:start -->
Reviewed summary
<!-- codex-security-release-summary:end -->
Generated notes
The workflow preserves that marked summary and replaces the generated section. After any recovery or repair, repeat every verification step above and review the final public release body.