Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 53 additions & 48 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ name: Release
# check:release-package-contents` (Layer 2 — fresh-surface contract per
# ADR-0021 / SPEC-V05-010), `actions/attest-build-provenance` for the
# workflow-built tarball, `gh release create` for the canonical `vX.Y.Z` tag
# on `main` per ADR-0020, `npm publish` to npmjs.com via classic NPM_TOKEN
# (ADR-0041 — interim fallback to ADR-0040 Trusted Publishing, tracked in
# issue #411), and `gh release upload` to attach the package tarball as a
# release asset.
# on `main` per ADR-0020, `npm publish --provenance` to npmjs.com via
# Trusted Publishing (ADR-0044 restoring ADR-0040 after the ADR-0041
# NPM_TOKEN fallback used for v0.7.0 / v0.7.1), and `gh release upload` to
# attach the package tarball as a release asset.
#
# Inputs and the confirm gate satisfy SPEC-V05-002 (explicit publish
# authorisation), SPEC-V05-003 (GitHub Release publication), SPEC-V05-004
Expand Down Expand Up @@ -50,16 +50,16 @@ on:
required: false
default: false

# Least-privilege workflow permissions per ADR-0020 / ADR-0040 / ADR-0041 /
# Least-privilege workflow permissions per ADR-0020 / ADR-0040 / ADR-0044 /
# SPEC-V05-002 / NFR-V05-001. `REQUIRED_WORKFLOW_PERMISSIONS`
# (scripts/lib/release-readiness.ts) enforces the top-level block as exactly
# { contents: write, attestations: write, id-token: write }; job-level
# overrides may only narrow, never widen. `contents: write` for
# `gh release create` + upload, `attestations: write` to persist GitHub
# Release tarball attestations, `id-token: write` for the
# `actions/attest-build-provenance` step that signs the GitHub Release
# tarball asset (kept across the ADR-0041 fallback so the GitHub Release
# asset retains its provenance even while npm provenance is paused).
# Release tarball attestations, `id-token: write` is now load-bearing for
# both attestation paths: it mints the OIDC token consumed by `npm publish
# --provenance` (ADR-0044) and the OIDC token consumed by
# `actions/attest-build-provenance` (Release tarball asset).
# zizmor: suppressed inline.
permissions: # zizmor: ignore[excessive-permissions,undocumented-permissions]
contents: write # zizmor: ignore[excessive-permissions]
Expand All @@ -74,16 +74,25 @@ jobs:
smoke:
name: Smoke test (release gate)
uses: ./.github/workflows/smoke-test.yml
permissions:
contents: read
# No job-level `permissions:` block — `scripts/lib/release-readiness.ts`
# `diagnosticsForPermissions` enforces strict equality between job-level
# and top-level permission values (line ~852: "is `<actual>` but must be
# `<expected>`"). A `contents: read` override here failed Layer 1
# readiness on the v0.8.0-rc.1 dispatch (run 25639883562). The smoke job
# therefore inherits the top-level `{ contents: write, attestations:
# write, id-token: write }` block. The reusable smoke-test workflow is
# read-only in practice (npm pack + install + CLI smoke); the inherited
# write scopes are unused.

release:
name: Manual GitHub Release
needs: smoke
runs-on: ubuntu-latest
# Deployment environment scopes `NPM_TOKEN` to release dispatches per
# GitHub's `secrets-without-environment` advisory and lets the operator
# add required-reviewer / wait-timer protection rules without changing
# Deployment environment matches the npmjs.com Trusted Publisher
# configuration (workflow=`release.yml`, environment=`release`) so the
# OIDC token minted by GitHub for this job authenticates the npm
# publish step. The environment also lets the operator add
# required-reviewer / wait-timer protection rules without changing
# the workflow. URL points at the just-published GitHub Release page.
environment:
name: release
Expand All @@ -97,13 +106,9 @@ jobs:

# `registry-url` writes `~/.npmrc` so `npm publish` resolves the
# registry to npmjs.com. The `scope` field is unnecessary because the
# package is unscoped (`specorator`), per ADR-0040.
#
# `NODE_AUTH_TOKEN` is supplied at the publish step (not here) via the
# `NPM_TOKEN` repo secret — a classic Automation token, per ADR-0041
# (interim fallback). When Trusted Publishing is unblocked (#411) the
# publish step will switch back to OIDC + `--provenance` and the
# `NPM_TOKEN` env will be removed.
# package is unscoped (`specorator`), per ADR-0040. No
# `NODE_AUTH_TOKEN` is set — Trusted Publishing (ADR-0044) supplies
# the auth token via OIDC at the publish step.
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
Expand Down Expand Up @@ -343,18 +348,19 @@ jobs:
--jq '.body' \
|| echo '(generate-notes preview unavailable; readiness diagnostics above remain authoritative)'

# Step 10 — publish the package to npmjs.com via classic NPM_TOKEN
# (ADR-0041, interim fallback to ADR-0040). The v0.7.0 release
# dispatch failed at this step with `404 PUT` because npmjs.com
# Trusted Publishing requires the publisher to be pre-registered
# against an existing package, and `specorator` did not exist at
# the time of the dispatch (chicken-and-egg). Subsequent attempts
# to configure Trusted Publisher on the now-existing package are
# currently blocked. `actions/setup-node` wrote `~/.npmrc` pointing
# at `https://registry.npmjs.org`; `NODE_AUTH_TOKEN` (set via the
# `NPM_TOKEN` repo secret — a classic Automation token) authenticates
# the publish. Tracking issue: #411. Re-enable OIDC + `--provenance`
# once Trusted Publisher is configured and verified.
# Step 10 — publish the package to npmjs.com via npmjs.com Trusted
# Publishing (ADR-0044, restoring ADR-0040 after the ADR-0041
# NPM_TOKEN fallback used for v0.7.0 / v0.7.1). The publisher is
# pre-registered on npmjs.com against this workflow file
# (`release.yml`) on the `release` deployment environment; the
# OIDC token minted via `id-token: write` authenticates the
# publish. `actions/setup-node` wrote `~/.npmrc` pointing at
# `https://registry.npmjs.org`; no `NODE_AUTH_TOKEN` is read.
# `npm publish --provenance` mints a sigstore provenance
# statement that ships with the tarball and is visible on the
# npmjs.com package page under `Provenance`. Tracking issue
# #411 closed when Trusted Publishing was activated on
# 2026-05-10.
#
# The pre-flight check short-circuits before `npm publish` if
# `package.json` drifted from `INPUT_VERSION` between Layer 1
Expand All @@ -376,29 +382,28 @@ jobs:
# - npm E404 → version genuinely not published, proceed.
# - any other failure (transient registry / auth / DNS) → fail
# closed.
#
# zizmor's `use-trusted-publishing` audit suggests OIDC trusted
# publishing instead of a token. Trusted Publishing is the
# documented target (ADR-0040) and intended return path; ADR-0041
# records the deferral. The audit is suppressed at the step
# boundary; revisit when issue #411 closes.
- name: Publish to npmjs.com # zizmor: ignore[use-trusted-publishing]
- name: Publish to npmjs.com
if: ${{ ! inputs.dry_run && inputs.publish_package }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_PRERELEASE: ${{ inputs.prerelease }}
TARBALL: ${{ steps.pack.outputs.tarball }}
run: |
if [ -z "${NODE_AUTH_TOKEN}" ]; then
echo "::error::NPM_TOKEN repo secret is not set — refusing to publish (ADR-0041 fallback requires a classic Automation token until issue #411 closes)" >&2
exit 1
fi
actual="$(node -p "require('./package.json').name + '@' + require('./package.json').version")"
expected="specorator@${INPUT_VERSION}"
if [ "$actual" != "$expected" ]; then
echo "::error::package.json identity (${actual}) does not match expected (${expected}) — refusing to publish (ADR-0040)" >&2
exit 1
fi
# Pre-release versions must publish under a non-`latest` dist-tag.
# `npm publish` refuses to default a prerelease to `latest` and
# exits with "You must specify a tag using --tag when publishing
# a prerelease version." `inputs.prerelease == true` → publish
# under `next`; stable releases → default `latest` (no `--tag`).
publish_args=("--provenance")
if [ "${INPUT_PRERELEASE}" = "true" ]; then
publish_args+=("--tag" "next")
fi
set +e
view_output="$(npm view "specorator@${INPUT_VERSION}" version --json 2>&1)"
view_exit=$?
Expand All @@ -408,9 +413,9 @@ jobs:
elif echo "$view_output" | grep -qE "\"code\": *\"E404\"|E404|code E404|404 Not Found"; then
# Publish the byte-identical tarball produced in step 5 so the
# published archive equals the GitHub Release asset uploaded in
# step 11 (T-V05-013). No `--provenance` flag — Trusted Publishing
# is deferred per ADR-0041 (#411).
npm publish "${TARBALL}"
# step 11 (T-V05-013). `--provenance` mints a sigstore provenance
# statement via the OIDC token (ADR-0044, restoring ADR-0040).
npm publish "${publish_args[@]}" "${TARBALL}"
else
echo "::error::npm view failed with a non-404 error — refusing to publish so EPUBLISHCONFLICT cannot mask a real failure" >&2
echo "$view_output" >&2
Expand Down
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,58 @@ All notable changes to Specorator are documented here. Format follows [Keep a Ch

---

## [v0.8.0-rc.1] — 2026-05-10

Release candidate for the v0.8.0 cycle. Smoke-tests npmjs.com Trusted Publishing on the `specorator` package after [ADR-0044](docs/adr/0044-restore-npmjs-trusted-publishing.md) restored the OIDC + `--provenance` path (supersedes ADR-0041). The first successful RC dispatch confirms `release.yml` mints an OIDC token, `npmjs.com` accepts the publish, and the package page surfaces a sigstore provenance attestation. Surface content is identical to the v0.8.0 final entry below.

---

## [v0.8.0] — 2026-05-10

### Changed

- **Plugin distribution moves to an orphan dist branch.** The Claude Code plugin bundle (`claude-plugin/specorator/{agents,skills,commands,.claude-plugin}/` + `.mcp.json`) is now gitignored on `develop` and `main` and published to the long-lived orphan branch `dist/claude-plugin` by `.github/workflows/publish-claude-plugin.yml` on every push to `main`. The marketplace entry in `.claude-plugin/marketplace.json` switched from a relative-path source to a `git-subdir` source pinned to that ref. Marketplace consumers transparently pick up the new bundle on `/plugin marketplace update`. ADR-0043 records the rationale and considered alternatives. Closes #461 (gitignore-the-bundle) and #474 (install-flow redesign).
- **npmjs.com Trusted Publishing restored** — `release.yml` step 10 reverts to OIDC + `npm publish --provenance`; `NODE_AUTH_TOKEN` env removed; `NPM_TOKEN` repo secret decommissioned; `# zizmor: ignore[use-trusted-publishing]` suppression dropped. Every v0.8.x release ships with a sigstore provenance attestation visible on the npmjs.com package page. ADR-0044 supersedes ADR-0041; closes #411. Operator-guide §1 (prereqs), §5 (publish step), §5.1 (provenance posture), and §7.1 (manual recovery) refreshed for the OIDC happy path.
- `npm run check:claude-plugin` is now structural-only on a clean `develop`/`main` checkout — generated-output checks (manifest, `.mcp.json`, agents/skills/commands directories) are conditional on the file being present. The `build:claude-plugin --check` drift check is no longer part of the verify gate.
- `.github/workflows/release.yml` now runs `npm run build:claude-plugin` before the readiness gate so the npm tarball still ships the bundle in `claude-plugin/specorator/`.
- ADR-0030 (repo-adoption track) withdrawn — superseded by the plugin-packaging path.

### Added

- **`/issue:tackle` conductor skill** — triage-first workflow for resolving a GitHub issue or PR end-to-end: classifies type/priority, scans for open tasks, proposes a resolution path, creates an isolated worktree, guides execution, and opens a PR (#443).
- **`/specorator:onboard`** — guided 5-step onboarding series scaffolded on first install. Idempotent; falls back to local Markdown when `gh` auth is missing (#460).
- **GitHub remote MCP server** wired into the project `.mcp.json` and the plugin bundle. Issue, PR, branch, and review-comment operations are now first-class for any agent in a Specorator project (#471).
- **`specorator --version` / `-v`** CLI flag — version reported from `package.json#version`, no more drift (#424). Bare `--version` and `-V` now exit `0` (#419).
- **Conductor-driven model-tier injection** for subagents — orchestrator skills can specify the model tier per dispatch (#440).
- **Plugin install smoke test** in CI — `.github/workflows/smoke-test.yml` packs the tarball, installs `specorator` globally, and asserts CLI subcommand exit codes (#427).
- **ADR-0042** — adopt typed-artifact reader seam to keep agent IO contracts auditable (#442).
- **ADR-0043** — distribute Claude Code plugin bundle from an orphan dist branch via `git-subdir`.
- **Plugin user manual** at `docs/how-to/install-claude-plugin.md` rewritten for the orphan-branch flow + plugin-first install path (#410, #431, #467).
- **Operational bot dry-run + drift checks** — `tests/scripts/operational-bots.test.ts` validates every PROMPT.md surface (#438).
- **Agentic control-plane threat model** at `docs/security/control-plane-threats.md` (#437).
- **Specorator product ladder** at `docs/specorator-product/product-ladder.md` and supporting proof-loop asset (#435, #436).
- **Automation contract** entry point at `docs/automation-contract.md` cross-referencing every automation surface (#434).

### Fixed

- `scripts/build-claude-plugin.ts` strips the `specorator/` prefix from canonical command paths so `/specorator:specorator:init` collapses back to `/specorator:init` in the published bundle (#420).
- `specorator init` warns when the target directory has no `.git` so adopters see the missing-VCS state before running through onboarding (#421).
- `/quality:status` and quality-related agents/skills now invoke the `specorator` CLI rather than raw `npm run` (#426, #428).
- Hardcoded `model: opus` removed from `architect`, `dev`, and `reviewer` subagents — the conductor sets the tier (#429).
- Quality status loader normalises historical status values (`done`, `complete`) to the canonical `completed` to silence loader warnings on legacy specs (#439).
- Product page deployment moved to a dedicated `gh-pages` branch — broken images on the public site fixed (#456).
- `.github/workflows/sync-github-archive.yml` sets the bot git identity before the merge step so scheduled syncs no longer fail at `nothing to commit` (#468).
- Feature-tracker test guards `readFile` against the ENOENT race when the page-data fixture is regenerated mid-run (#408).

### Internal

- `actions/setup-node` bumped to v6.4.0 across remaining workflows (#473).
- v0.7 spec stub backfilled at `specs/v07-npm-publish/` for traceability (#432).
- `docs/specorator-product/site-vision.md` defines the Astro product-page roadmap.
- 30+ merged PRs since v0.7.0 — see the GitHub Release notes for the full enumeration.

---

## [v0.7.0] — 2026-05-09

### Breaking
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Specorator — Agentic Development Workflow

![Version](https://img.shields.io/badge/version-v0.7.0-blue) ![License](https://img.shields.io/badge/license-MIT-green)
![Version](https://img.shields.io/badge/version-v0.8.0-blue) ![License](https://img.shields.io/badge/license-MIT-green)

[![Verify](https://github.com/Luis85/agentic-workflow/actions/workflows/verify.yml/badge.svg?branch=main)](https://github.com/Luis85/agentic-workflow/actions/workflows/verify.yml) [![gitleaks](https://github.com/Luis85/agentic-workflow/actions/workflows/gitleaks.yml/badge.svg?branch=main)](https://github.com/Luis85/agentic-workflow/actions/workflows/gitleaks.yml) [![typos](https://github.com/Luis85/agentic-workflow/actions/workflows/typos.yml/badge.svg?branch=main)](https://github.com/Luis85/agentic-workflow/actions/workflows/typos.yml) [![zizmor](https://github.com/Luis85/agentic-workflow/actions/workflows/zizmor.yml/badge.svg?branch=main)](https://github.com/Luis85/agentic-workflow/actions/workflows/zizmor.yml)

**Build software the right way with AI.** Specorator is a spec-driven workflow template: humans decide what to build, specialist agents handle how, and every requirement, decision, task, test, and release note stays traceable.

> **Status:** v0.7.0 — npm publication migrated from GitHub Packages (`@luis85/agentic-workflow`) to npmjs.com as `specorator` (unscoped, public). Adopters now run `npm install -g specorator` with no `.npmrc` configuration or PAT. Trusted publishing via OIDC is deferred per [ADR-0041](docs/adr/0041-defer-npmjs-trusted-publishing.md) (tracking [#411](https://github.com/Luis85/agentic-workflow/issues/411)) — v0.7.x publishes via classic `NPM_TOKEN` and ships without npm provenance attestations until the trusted publisher path is unblocked. The GitHub Release tarball asset still carries a sigstore attestation. v0.6.2 patched the Layer 1 readiness `refs/heads/main` lookup. v0.6.1 shipped Specorator as a Claude Code plugin. v0.6.0 introduced the Astro 6 product page. Claude Code is first-class; Codex, Cursor, Aider, Copilot, and Gemini have Markdown-based walkthroughs. **Breaking:** the GitHub Packages package `@luis85/agentic-workflow` is deprecated; existing versions still install but new releases land only on npmjs.com.
> **Status:** v0.8.0 — Claude Code plugin bundle moves to a long-lived orphan branch (`dist/claude-plugin`) rebuilt by CI on every push to `main`; the marketplace entry now uses a `git-subdir` source pinned to that ref ([ADR-0043](docs/adr/0043-distribute-claude-plugin-bundle-from-orphan-dist-branch.md)). Bundle is gitignored on `develop`/`main`, so PR diffs stop carrying generated-artifact churn. New `/issue:tackle` conductor skill, `/specorator:onboard` guided issue series, GitHub remote MCP server in the project default, conductor-driven model-tier injection for subagents, and `specorator --version` flag. npmjs.com Trusted Publishing restored ([ADR-0044](docs/adr/0044-restore-npmjs-trusted-publishing.md), supersedes ADR-0041); every v0.8.x release ships with a sigstore provenance attestation visible on the npmjs.com package page. v0.7.0 migrated the npm CLI from GitHub Packages to npmjs.com as `specorator` (unscoped, public, no `.npmrc`). Claude Code is first-class; Codex, Cursor, Aider, Copilot, and Gemini have Markdown-based walkthroughs.

Product page: <https://luis85.github.io/agentic-workflow/>

Expand Down
6 changes: 3 additions & 3 deletions docs/adr/0041-defer-npmjs-trusted-publishing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
id: ADR-0041
title: Defer npmjs.com Trusted Publishing — fall back to NPM_TOKEN
status: accepted
status: superseded
date: 2026-05-09
deciders:
- maintainer
Expand All @@ -10,15 +10,15 @@ consulted:
informed:
- template adopters
supersedes: []
superseded-by: []
superseded-by: [ADR-0044]
tags: [release, distribution, security]
---

# ADR-0041 — Defer npmjs.com Trusted Publishing — fall back to NPM_TOKEN

## Status

Accepted
Superseded by [ADR-0044](0044-restore-npmjs-trusted-publishing.md) on 2026-05-10. npmjs.com Trusted Publisher was activated against `release.yml`; the OIDC + `--provenance` path is restored beginning with the v0.8.0 release dispatch. Tracking issue #411 closed.

## Context

Expand Down
Loading
Loading