@@ -95,18 +95,17 @@ stay unpublished. There are three channels:
9595- ** Nightly** (` npm install -g agent-device@nightly ` ): every few hours the workflow checks ` main ` .
9696 It publishes ` X.Y.Z-nightly.<YYYYMMDD>.<run> ` under the ` nightly ` dist-tag when ` main ` 's HEAD has
9797 changed since the last nightly, its CI passed, and no nightly shipped that UTC day. It then tags
98- the commit ` v<nightly version> ` . To publish one now, run ** Release** with ` channel: nightly ` .
99- - ** Stable** (` latest ` ): run ** Release** with ` channel: stable ` . It promotes the latest nightly's
100- commit, by default as the ` X.Y.Z ` that nightly previewed. Set ` version ` to release it under
101- another number. The run tags that commit ` vX.Y.Z ` and starts the stable run on the tag. The stable
102- run waits for approval in the ` release ` environment, then publishes the packages, drafts the GitHub
103- release with generated notes, attaches the iOS runner and Android helper assets, publishes the
104- release and the MCP Registry entry, and commits ` main ` 's next ` -dev ` version. Pushing a ` vX.Y.Z `
105- tag yourself starts the same stable run for that commit.
98+ the commit ` nightly/v<nightly version> ` . To publish one now, run ** Release** on ` main ` .
99+ - ** Stable** (` latest ` ): a repository admin runs ` pnpm release:promote ` . It pushes ` vX.Y.Z ` at the
100+ latest nightly's commit, by default as the ` X.Y.Z ` that nightly previewed; pass a version, such as
101+ ` pnpm release:promote 0.22.0 ` , to release it under another number. The tag's ** Release** run waits
102+ for approval in the ` release ` environment, then publishes the packages, drafts the GitHub release
103+ with generated notes, attaches the iOS runner and Android helper assets, publishes the release and
104+ the MCP Registry entry, and commits ` main ` 's next ` -dev ` version.
106105- ** Dry run** : a pull request that changes release tooling builds and verifies every package with a
107106 nightly version, and publishes nothing.
108107
109- To retry a failed run, re-run its failed jobs. The publisher skips package versions that are already
108+ To retry a failed run, re-run its failed jobs, or run ** Release ** on the release tag . The publisher skips package versions that are already
110109on npm, so a partial publish completes on the next attempt. To preview the packages locally, run
111110` pnpm release:prepare ` . It builds, verifies, and packs every public package into ` .tmp/release ` .
112111
@@ -131,6 +130,40 @@ npm trust github @agent-device/<name> --file release.yml --repository callstack/
131130npm access set mfa=publish @agent-device/< name>
132131```
133132
133+ ### One-time repository setup
134+
135+ npm trusts every run of ` release.yml ` that reaches the ` npm-publish ` environment, so GitHub
136+ settings, not the workflow, decide who can publish. The plan job refuses to publish until the first
137+ three are in place. Apply them before granting npm trust:
138+
139+ 1 . ** Environment ` npm-publish ` ** (Settings → Environments): deployment branches and tags limited to
140+ the branch ` main ` and the tag pattern ` v* ` . No reviewers and no secrets, so nightlies run
141+ unattended.
142+ 2 . ** Environment ` release ` ** : required reviewers. Turn on "Prevent self-review" only when another
143+ maintainer can approve, because the admin who pushes the tag cannot approve their own run.
144+ 3 . ** Tag ruleset** (Settings → Rules → Rulesets → New tag ruleset): active, targeting
145+ ` refs/tags/v* ` , restricting creations, updates, and deletions, with only the Repository admin
146+ role allowed to bypass. Nightly tags live under ` nightly/ ` and stay outside it.
147+ 4 . ** Actions** (Settings → Actions → General): workflow permissions set to read repository contents,
148+ and "Allow GitHub Actions to create and approve pull requests" turned off.
149+
150+ Confirm the result, then grant npm trust to each public package and, once a nightly has published,
151+ refuse token-based publishing:
152+
153+ ``` bash
154+ gh api repos/callstack/agent-device/environments/npm-publish/deployment-branch-policies \
155+ --jq ' .branch_policies[] | "\(.type) \(.name)"' # branch main, tag v*
156+ gh api repos/callstack/agent-device/environments/release \
157+ --jq ' .protection_rules[] | select(.type == "required_reviewers")'
158+ gh api repos/callstack/agent-device/rulesets --jq ' .[] | select(.target == "tag") | .name'
159+ npm trust github < package> --file release.yml --repository callstack/agent-device \
160+ --environment npm-publish --allow-publish --yes
161+ npm access set mfa=publish < package>
162+ ```
163+
164+ Anyone who can push to ` main ` can still change what the next nightly publishes; ` main ` does not
165+ require pull requests.
166+
134167### The version on main never equals a published version
135168
136169` main ` carries ` X.Y.Z-dev ` , naming the release it is building towards. Nightlies preview it as
0 commit comments