docs(openspec): propose nightly CLI builds - #116
Conversation
Adds the nightly-cli-builds change: publish @taskless/cli-nightly from main, and split release.yml into one workflow per release design. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
Swaps the last two units of the nightly stack. The nightly now lands before Vale moves to `npm-autopublish`, rather than after. The reason is the trusted-publisher risk the proposal already names. npm bindings can be scoped to a GitHub environment, and if the six `@taskless/vale-*` bindings are, moving Vale first invalidates all of them and the next publish fails the OIDC handshake with no stored token to fall back on. That trades a working release path for a convenience. The nightly exercises the same environment, the same handshake, and the same trusted-publishing model on a package where failure is free: `@taskless/cli-nightly` is new, nothing resolves it, and a failed first publish blocks nobody. Whatever the binding model turns out to require is learned there. By the time Vale moves, the destination is proven. Stated generally, since it outlives this change: prove a new credential path on something disposable before migrating something that works onto it. Both human-gated prerequisites move up accordingly — the environment and the `@taskless/cli-nightly` binding are now needed before the nightly unit rather than before the Vale one. The archive moves to the Vale PR, which is now the tip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
There was a problem hiding this comment.
Pull request overview
Adds an OpenSpec proposal describing how to publish nightly CLI builds from main as a separate npm package (@taskless/cli-nightly) and how to split existing release workflows so each workflow file documents a single trust boundary/release design.
Changes:
- Adds a task plan for a 3-PR stacked delivery (workflow split → nightly publish → move Vale to autopublish environment).
- Adds new/modified OpenSpec requirements for nightly publishing, workflow trust boundaries, and Vale platform package publishing.
- Adds proposal/design documents plus
.openspec.yamlmetadata for the change.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| openspec/changes/nightly-cli-builds/tasks.md | Step-by-step delivery plan, prerequisites, and acceptance checks for the nightly + workflow split. |
| openspec/changes/nightly-cli-builds/specs/vale-binary-packages/spec.md | Updates requirements describing Vale platform-package publishing workflow and gating. |
| openspec/changes/nightly-cli-builds/specs/infrastructure/spec.md | Adds infrastructure requirements for workflow separation, credential-free gates, environments, and concurrency. |
| openspec/changes/nightly-cli-builds/specs/cli-nightly-builds/spec.md | Adds requirements defining nightly package identity, versioning, gating, and provenance expectations. |
| openspec/changes/nightly-cli-builds/proposal.md | High-level proposal summary (what/why/impact) for nightly publishing and workflow split. |
| openspec/changes/nightly-cli-builds/design.md | Detailed design rationale and trade-offs for the proposed workflows and security model. |
| openspec/changes/nightly-cli-builds/.openspec.yaml | OpenSpec metadata for the new change proposal. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@claude /review |
|
Claude finished @thecodedrift's task in 4m 8s —— View job Review of #116 — propose nightly CLI builds
This is a proposal-only PR (528 lines, all new OpenSpec markdown/yaml, no workflow code yet), and the reasoning in Left 3 inline comments, roughly in order of severity:
No correctness issues found in the delta specs' scenario/requirement structure against the existing base specs ( Branch: |
Two of these were claimed as fixed in the PR description and were not actually in the artifacts — an implementer following the tasks would have reproduced both bugs the description said were handled. Select the proposed version by package name, never by index. `changeset status` returns an array of every package it releases, and `[0]` is the CLI only while the CLI is the sole managed package. The six vale packages already sit in the changesets ignore list, so a second managed package is not hypothetical. Taking `[0]` would stamp a nightly with another package's version — a wrong version that publishes cleanly and looks plausible. Now stated in the task, the design, and the spec, with a scenario. Record why there is no tag bookkeeping. `latest` is correct for every version this package produces, so there is no channel to maintain and no state to drift. The reviewer's case — a publish that lands while the tag move does not — is accepted rather than mitigated: the window closes at the next nightly, and gate 2 skipping a re-run of identical bytes is right on its own terms. Written down, because "we thought about this" and "we did not think about this" are indistinguishable from silence. Scope the PR 1 changeset to PR 1. The stack merges forward, where CLAUDE.md requires each unit to extend the changeset with what it landed rather than the base promising everything up front. Also: the group cross-reference in 1.8 was left pointing at the pre-reorder numbering, and task 0.3 asked to confirm a "currently published" name is "unclaimed". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
All three addressed in The first finding was the valuable one, and it was a defect in the PR description rather than the proposal: two gaps were described as "captured as tasks" when they existed only in the prose about the artifacts. An implementer following task 4.2 would have reproduced the The tag-blindness gap resolved as documentation rather than mechanism. — AI Coding Agent |
|
@claude /review |
|
Claude finished @thecodedrift's task in 4m 37s —— View job Review of #116 — propose nightly CLI builds
This pass re-reviewed the proposal after Found 3 new issues, all in artifacts this proposal is entirely responsible for getting right since there's no code yet — left as inline comments:
Everything else re-verified clean: the |
…ds PR 2 Three findings from the re-review, the first two of which would have shipped as bugs. `.changeset/` is never empty. It permanently holds `README.md` and `config.json` — `changesets init` writes both and nothing removes them — so a literal emptiness test answers "pending" on every push, including the Version Packages merge that D4 claims it self-handles. The gate is "any `.changeset/*.md` other than `README.md`", which is exactly how `require-changeset.yml` already counts them; reuse that rule rather than inventing a second one. Group 3 could not run where it was placed. It publishes the tarball from the pack script in task 4.1, and 4.1 is part of PR 2 — the PR group 3 is meant to precede. Introduced when the units were reordered to put the nightly ahead of the Vale move: before that swap the binding step came after the nightly PR, so the script existed. It now says what it always meant — open PR 2, run its pack script from that branch, publish and bind, then merge. Vale's equivalent reads as a clean prerequisite only because `vale-prepare.cjs` was already on `main`. Also the third stale cross-reference from the same renumbering: the Vale-bindings check is task 5.3, not 4.2. Found by the first review round that could read whole files rather than diff hunks, after the review workflow was fixed to check out the PR ref.
Stack (root → tip):
Proposal only — no implementation. Artifacts for a nightly build of the CLI published from
mainas a separate package, plus a split of the release workflows so each carries one design.What it proposes
@taskless/cli-nightly, published frommain, versionn.m.k-yyyymmddhhmmssx<sha>.changeset/empty (a directory listing, before any install), and is this SHA already builtnpm-autopublishenvironment for flows that publish without a human clickrelease.ymlandvale-binaries.yml, each with one trust storyThe design is argued in #111;
design.mdrecords the decisions with their reasoning rather than restating the conclusions.Built from
main, not from PRsThe original framing was "on PR update". That is what the title of #111 said until this proposal was written, and it does not survive contact with
release.yml's security model: a PR-triggered publish would route contributor-authored changeset text into a credentialed job, inverting the split that file exists to maintain, and would publish unreviewed code under the@tasklessscope.Tying builds to changeset edits does not work either. Measured on the #71→#106 stack,
add-vale-rule-enginehad 7 commits after its last changeset edit andagent-command-and-vale-authoringhad 11 — a nightly stamped at changeset-edit time would omit all of them while looking current.Delivery: stacked, merging forward, three PRs
release.yml's header, which claims "No required reviewers … by design" whilenpm-productiondemonstrably has a required reviewer.npm-autopublishand registering trusted publishing.npm-autopublish— tip, archives the change.The nightly deliberately precedes the Vale move. npm trusted-publisher bindings can be scoped to a GitHub environment. If the six
@taskless/vale-*bindings are, moving Vale first invalidates all of them and the next publish fails the OIDC handshake with no stored token to fall back on — trading a working release path for a convenience. The nightly exercises the same environment, handshake, and binding model on a package where failure is free: nothing resolves@taskless/cli-nightly, so a failed first publish blocks nobody. Stated generally indesign.md, because it outlives this change: prove a new credential path on something disposable before migrating something that works onto it.Two prerequisites no implementer can satisfy
Called out in the proposal body rather than buried in tasks, because they gate merges:
npm-autopublishenvironment must be created in repo settings — no required reviewers, branch policy onmain.@taskless/cli-nightlymust be published once manually and a trusted-publisher binding registered. Trusted publishing is per-package, and the package does not exist yet.Both sit as maintainer task groups before the nightly unit. A PR waits rather than merging with a dangling environment reference.
Gaps this surfaced in #111
Writing the design down found four things the discussion had left implicit, all captured as tasks:
changeset statusreturns an array; taking[0]breaks the day a second changesets-managed package appears. Filter by name.npm view … versionslists versions regardless of tag, so a version that published but failed to get tagged reads as already-built and is skipped forever. The Vale workflow handles that case explicitly; nightly's was left implicit.mainrequiresValidate; any branch-protection or breadcrumb reference to an old name silently stops reporting.openspec validate --all --strict: 24 passed, 0 failed.No changeset — a proposal ships nothing.
Refs #111