The lint-prod step crashes today on a pre-existing snapshot bug (GraphQL
schema query for a "domains" field that no longer exists on Project).
The `--exit-zero` flag only suppresses exit-on-findings — it doesn't
catch fatal Ruby errors during snapshot building, so an error short-
circuits the whole job and the visibility surfaces never render.
Make the workflow truly advisory:
- Capture lint-prod stderr + exit code instead of failing the step.
- If lint-prod errors (or produces no JSON), synthesize a minimal
payload with an "error" field so the renderer has something to chew on.
- Renderer detects the error field and emits an "audit unavailable" block
with the captured error inside a <details> fold instead of leaving the
step summary / sticky comment blank.
Snapshot bug itself is out of scope for this change; tracked separately.
Make the lint-prod audit result legible without having to click into the
workflow logs. Two surfaces, both rendered from the same JSON payload:
1. `$GITHUB_STEP_SUMMARY` — structured markdown block at the top of every
workflow run page. Shows on every event (push, pull_request,
workflow_dispatch).
2. Sticky PR comment — one comment per PR, keyed by the HTML marker
`<!-- lint-prod-sticky-comment -->`. Re-runs update the same comment via
`gh api -X PATCH` instead of creating duplicates. Plain `gh` CLI only,
no third-party action.
Both surfaces show: one-line status, a table of the unpinned services only
(not all 27), and a Pacific-time run timestamp with the finding count.
To support the renderer, add `--format json` to `lint-prod`:
{services:[{name,source,status}], findings:N, timestamp:"ISO8601"}
The workflow consumes this shape and also writes `findings` to
`$GITHUB_OUTPUT` so downstream jobs (future Slack alert) can compare runs.
Idempotent: re-running the workflow finds the existing comment by marker
and PATCHes it — never duplicates.
Add --exit-zero flag to bin/railway lint-prod that makes the command exit 0
even when digest-pinning findings exist. Findings still print to stdout so
they remain visible in the CI step log.
Wire the showcase_lint_prod.yml workflow to pass --exit-zero so the job
cannot block PRs while we soak the check against real production state.
Once we have confidence the findings are clean, remove --exit-zero from
the workflow step to flip lint-prod to enforcing.
Updates README to document the advisory-mode behavior and the path to
flipping the check to enforcing.
Prerelease canary publishing is now an input mode on publish-release.yml's
workflow_dispatch. The dedicated prerelease.yml workflow is no longer
reachable and its workflow_call delegation never worked (npm matches the
OIDC token's caller `workflow_ref`, which was always prerelease.yml —
unregistered with any package's trust record).
Canaries are now dispatched via:
gh workflow run publish-release.yml \
-f scope=monorepo -f mode=prerelease -f suffix=<name>
The `bump-prerelease.ts` and `prerelease.ts` scripts remain unchanged; they
are invoked by publish-release.yml when `mode=prerelease`.
Folds prerelease.yml's canary publishing back into publish-release.yml, which
is the workflow registered as npm trusted publisher for all 15 @copilotkit/*
monorepo packages and @copilotkitnext/angular. Since npm matches on the OIDC
token's `workflow_ref` claim (the caller), the canary must dispatch from THIS
workflow file — not from a separate workflow that delegates via workflow_call.
Changes:
- Add `mode` (stable|prerelease) and `suffix` inputs to workflow_dispatch.
`mode` selects the publish script and gates post-publish tag/release steps;
`suffix` is forwarded to bump-prerelease.ts when mode=prerelease.
- Add a conditional `Bump prerelease versions` step in the build job that
runs `scripts/release/bump-prerelease.ts` before `Build packages` whenever
`inputs.mode == 'prerelease'`. The bumped versions flow through the
workspace artifact to the publish job exactly as in the deleted
prerelease.yml.
- Switch the publish step's `PUBLISH_SCRIPT` env var to be mode-driven:
`prerelease.ts` for canaries, `publish-release.ts` for stable. The old
`inputs.publish-script` plumbing was removed in the prior commit along
with the workflow_call inputs schema.
- Simplify the publish-job `meta` step now that workflow_call is gone: mode
defaults to `stable` unless workflow_dispatch passes `prerelease`.
- Rewrite the top-of-file comment to document both modes and the OIDC trust
binding, replacing the old "MANUAL RETRIGGER" wording which only covered
the stable retrigger path.
All post-publish gating (`steps.meta.outputs.mode != 'prerelease'` on the tag,
release, and stable-summary steps; `mode == 'prerelease'` on the prerelease
summary) was already in place from the prior PR-A architecture and is left
intact. The `Verify publish step emitted version` step keeps its prerelease
bypass.
Canary invocation after this lands:
gh workflow run publish-release.yml \
-f scope=monorepo -f mode=prerelease -f suffix=<name>
The workflow_call trigger was added in the PR-A/B architecture so prerelease.yml
could invoke this workflow as a reusable workflow. That architecture was wrong:
npm's trusted-publisher matching uses the OIDC token's `workflow_ref` claim,
which is the CALLER workflow (prerelease.yml), not the callee's
`job_workflow_ref` (publish-release.yml). Since prerelease.yml has no trust
record, every canary attempt failed at the npm publish step with ENEEDAUTH.
This commit removes the dead code:
- workflow_call: trigger block (inputs schema + secrets block)
- the `github.event_name != 'workflow_call'` guard on the build job
- the `needs.build.result == 'skipped' && github.event_name == 'workflow_call'`
branch on the publish job's `if:` (simplified to plain success check)
The follow-up commit folds prerelease support back into this workflow as a
`workflow_dispatch` mode, so the canary path executes from the workflow with
the trust record.
## Why
Follow-up to #5063. Together they unblock customer canary publishes that
have been failing with `npm ENEEDAUTH` since 2026-05-15.
#5063 parametrized `publish-release.yml` to support `workflow_call`.
This PR converts `prerelease.yml`'s publish path into a thin caller of
that reusable workflow. Because npm OIDC's `job_workflow_ref` claim
resolves to the callee in a reusable-workflow invocation, the existing
trust record on `publish-release.yml` covers both stable AND canary
publishes — no second trusted-publisher record needed (npm only allows
one per package).
## What changes
- `prerelease.yml`'s `build` job is preserved verbatim (checkout,
install, `bump-prerelease.ts --suffix`, build, test, upload `workspace`
artifact).
- The old `publish` job is replaced with `uses:
./.github/workflows/publish-release.yml` with `mode: prerelease`,
`publish-script: prerelease.ts`, `scope`, `dry-run`.
- The caller's `publish` job grants explicit `permissions: { contents:
write, id-token: write, actions: read }` — REQUIRED for the callee's npm
OIDC mint (per GitHub Actions, caller's per-job permissions cap the
callee's declared permissions).
- The caller's `workflow_dispatch.inputs.dry_run` (underscore, preserved
for backwards compat) maps to the callee's `dry-run` (hyphen) at the
`with:` boundary.
- No `secrets:` block — Notion not needed for prereleases; callee
declares `NOTION_API_KEY` optional and gates it on `mode == 'stable'`.
## Verification plan
1. Dispatch `prerelease.yml` with `scope: monorepo`, `suffix:
test-oidc-refactor`, `dry_run: true` → confirms plumbing without an
actual publish.
2. Dispatch again with `dry_run: false` → first OIDC-handshake-verifying
real canary.
3. `npm view @copilotkit/runtime@1.58.0-canary.test-oidc-refactor --json
| jq '.dist.attestations'` → confirm provenance attestation references
`publish-release.yml`.
## Test plan
- [ ] CI green.
- [ ] Post-merge: dispatch dry-run + real canary per Verification plan
above.
- [ ] Confirm provenance attestations land via `npm view`.
Supersedes #5066 (closed when #5063's base branch was deleted).
## Summary
- Unify authored and generated shell-docs navigation so the sidebar
keeps the same structure across framework modes.
- Restore setup-content bundling from integration-owned docs and wire
shell-docs to consume the generated bundle at runtime.
- Audit and fix the LangGraph TypeScript and Google ADK code regions so
the generated snippets are more useful and accurate.
- Tighten docs/build routing and workflow triggers so shell-docs
rebuilds when the relevant integration docs inputs change.
## Testing
- Shell-docs unit tests passed.
- Shell-docs typecheck passed.
- Shell-docs lint passed with existing repository warnings only.
- Setup-content bundle generation passed.
- Python integration files compiled successfully.
- Workflow YAML parsed successfully.
PR-B CR-r1 fix: reusable-workflow permissions in GitHub Actions are capped by
the caller's per-job permissions. The callee (publish-release.yml from PR-A)
declares id-token: write + contents: write on its publish job, but without
the caller (prerelease.yml) granting those at its own publish-job level, the
callee gets only the workflow-level default (contents: read). The OIDC token
mint then fails silently and npm publish errors.
4 of 7 CR agents independently flagged this. The spec missed it.
Adds contents: write (callee uses it in stable mode; gated off in prerelease
but matches the callee's declaration), id-token: write (required for OIDC),
and actions: read (required for actions/download-artifact in callee).
Spec updated to document this requirement.
PR-B of the two-PR refactor: prerelease.yml's build job is preserved verbatim
(checkout, install, bump-prerelease.ts with --suffix, build, test, upload-
artifact "workspace"); its publish job is replaced with a workflow_call
invocation into publish-release.yml from PR-A. The reusable workflow's
job_workflow_ref OIDC claim matches the existing trusted-publisher record on
publish-release.yml, so the canary publishes succeed without registering a
second trust binding (which npm does not allow).
The caller's workflow_dispatch.inputs.dry_run (underscore, preserved) maps
to the callee's dry-run (hyphen) at the with: boundary — independent keys
in independent namespaces. No secrets passed; Notion not needed for
prereleases.
Spec: https://www.notion.so/36d3aa381852811ba10ad1bcd228d6d8
Unblocks: @copilotkit/react-core canary --suffix thread-id-propagation.
Stacked on PR-A (fix/publish-release-workflow-call).
PR-A CR-r2 fixes (2 bucket-(a) findings from 7-agent confirmation round).
A4: Tighten publish-job `if:` so `needs.build.result == 'skipped'` is only honored when
the event is `workflow_call` (the intentional skip for the reusable workflow callee).
Previously, a `pull_request: closed` event on a release branch where the PR was closed
WITHOUT merging would cause the build job to skip (its own merged-true guard), then the
publish job's permissive `if:` would still run it — a phantom publish from an unmerged
release PR.
A5: Every post-publish step's custom `if:` overrode the default implicit `success()`
check, meaning a failure in `Publish to npm` or the `Verify version` guard would not
prevent downstream steps (tag push, GitHub Release create) from running. Prepended
`success() && ` to all post-publish step `if:` conditions to restore the implicit gate.
Spec: https://www.notion.so/36d3aa381852811ba10ad1bcd228d6d8
PR-A CR-r1 fixes (4 of 4 actionable findings from 7-agent CR + 1 cheap defense-in-depth).
A1: post-publish steps (Configure git user, Check for pre-existing tags, Create and push
git tag, Create GitHub Release) now gate on `inputs.dry-run != true && mode != 'prerelease'`
instead of just `mode`. On dry-run + stable, VERSION was empty so TAG="v" garbage was
pushed; this prevents that.
A2: Add explicit Verify-publish-step-emitted-version guard between Publish to npm and the
post-publish chain. Fails loud if publish-release.ts (or any inputs.publish-script
override) forgets to emit `version` to GITHUB_OUTPUT.
A3: Replace the single unconditional Release summary with three gated variants (stable,
prerelease, dry-run) so the summary no longer claims "Release Published" on dry-run or
prerelease.
B3: inputs.publish-script and steps.meta.outputs.scope now flow through env to the shell
(reduces injection surface even though caller is in-repo today).
Spec: https://www.notion.so/36d3aa381852811ba10ad1bcd228d6d8
prerelease.yml cannot register as a second npm trusted publisher (npm allows
exactly one per package; all 16 monorepo-scoped packages bind to
publish-release.yml). Refactor publish-release.yml to also support
workflow_call so prerelease.yml can invoke it as a reusable workflow — OIDC's
job_workflow_ref claim points at the callee, so the existing trust record
covers both flows.
This PR (PR-A) adds the workflow_call trigger, input schema, meta step for
scope+mode resolution, build-job gating to skip on workflow_call, publish-job
if: override for skipped-needs, post-publish step gating on
mode != prerelease, NOTION_API_KEY gating on stable mode, and the
publish-script input for the TS file selection.
Also adds a dry-run input on workflow_dispatch so PR-A can be verified
post-merge via a sacrificial release branch without an actual publish.
Spec: https://www.notion.so/36d3aa381852811ba10ad1bcd228d6d8
Customer block (Ben Taylor, #engr): @copilotkit/react-core canary with
suffix=thread-id-propagation.
PR-B (prerelease.yml caller conversion) follows.
The prerelease workflow has been OOMing on Upload workspace since the
build/publish split in 770759a4be. The artifact upload enumerates
~6M files (root + per-package node_modules with pnpm symlinks all
materialized, plus build caches) and actions/upload-artifact builds
the full manifest in memory before streaming, blowing past the 4GB
Node heap limit.
publish-release.yml already had the working pattern: exclude
node_modules/.next/.turbo/.nx and re-run pnpm install --frozen-lockfile
in the publish job. Port it over so prerelease publishes succeed
again.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zizmor's ref-version-mismatch audit flags the existing `# v1` comment
because the hash 5f3b3c2e5a00f0093de47f657aeaefcedff27d18 is the
v1.17.0 tag, not the v1 head. Update the trailing comment to match.
No behavior change — the SHA pin is what governs which commit Actions
fetches. This just keeps zizmor green so unrelated showcase-wiring PRs
don't trip on a pre-existing pin annotation.
Three companion workflows duplicate the showcase_build.yml service registry
and were missed in the initial wiring commit. Bring them in sync:
- .github/workflows/showcase_build_check.yml: add ms_agent_harness_dotnet
to the paths-filter and the ALL_SERVICES matrix (mirror of the
production build matrix, used for pre-merge Docker build verification).
- .github/workflows/showcase_deploy.yml: add ms-agent-harness-dotnet to
the workflow_dispatch options and the verification ALL_SERVICES with
railway_id 6343d7f9-6c3f-4c8d-9a6e-79f03d2f1e37 and /api/health.
- .github/workflows/showcase_keep-alive.yml: add ms-agent-harness-dotnet
to the keep-alive ping matrix.
Brings the Microsoft Agent Harness (.NET) integration live on the
showcase Railway project. Integration code itself landed in PR #4982.
Changes:
- Railway service `showcase-ms-agent-harness-dotnet` created
(id 6343d7f9-6c3f-4c8d-9a6e-79f03d2f1e37) with the public domain
showcase-ms-agent-harness-dotnet-production.up.railway.app, image
source ghcr.io/copilotkit/showcase-ms-agent-harness-dotnet:latest,
healthcheck /api/health, and env vars cloned from the sibling
showcase-ms-agent-dotnet service.
- .github/workflows/showcase_build.yml: add ms-agent-harness-dotnet to
workflow_dispatch options, paths-filter, and the ALL_SERVICES matrix
(mirroring the ms-agent-dotnet sibling entry).
- showcase/integrations/ms-agent-harness-dotnet/manifest.yaml: flip
deployed: false -> true so the dashboard surfaces the integration
once the image is live.
Skips test-and-check-packages pre-commit hook locally because
@copilotkit/web-inspector:test has a pre-existing failure on main
(window.localStorage.clear telemetry test setup) unrelated to these
YAML-only changes.
publish-release.ts now checks npm for each package before publishing
and skips versions that already exist. Makes publish idempotent —
safe to retry after partial failures. Removes the publish-remaining
one-shot workflow that's no longer needed.
Packages without repository.url fail npm OIDC provenance verification.
Adds the field to agentcore-runner, core, sqlite-runner, voice, and
web-inspector. Includes a one-shot workflow to publish the 14 remaining
v1.57.4 packages (a2ui-renderer already published via OIDC).
Replace pnpm publish with pnpm pack + npx npm@11.15.0 publish to
enable OIDC authentication. Set NODE_AUTH_TOKEN='' to prevent the
expired secret from blocking OIDC. Removes test workflow.
Without --bare, claude -p launches MCP servers defined in the project-level
.mcp.json before the model loads. A PR replacing .mcp.json with a malicious
entry gets an attacker-controlled subprocess launched on the CI runner —
same RCE surface as a SessionStart hook.
This repo already has .mcp.json committed (nx-mcp). Removing it before the
social copy generator runs is safe: the workflow's --allowedTools already
restricts Claude to specific read/diff tools and MCP servers are not needed
for social copy generation.
Call-site enumeration: rm -f is self-contained, no callers.
Extends the security fix to also cover .claude/settings.local.json, which
Claude Code reads with equal authority to settings.json. A PR author can
force-commit a gitignored file, so the .gitignore entry does not protect
against this vector.
Also moves the removal step to immediately after Checkout (before any other
step runs in the checked-out workspace), rather than after Install Claude Code.
Claude is not invoked during the intermediate steps, but this ordering is
strictly more defensive and prevents any future step insertions from reopening
the window.
Call-site enumeration: rm -f has no callers; step is self-contained YAML.
- Switch STORE_PATH from $GITHUB_ENV to $GITHUB_OUTPUT (step-scoped,
per GitHub Actions security hardening guide)
- Narrow hashFiles glob from '**/pnpm-lock.yaml' to 'pnpm-lock.yaml'
(root-only, avoids spurious cache busts from docs/examples lockfiles)
- Reword comment to show ABI mismatch is symmetric across all versions
- Document that actions/cache is equally fork-safe (GitHub platform guarantee)
pnpm rebuild better-sqlite3 was a no-op — pnpm treats the arg as a
workspace package name and exits silently when none matches.
Root fix: replace setup-node's built-in cache: "pnpm" (whose key omits
the Node.js version) with a manual actions/cache step that includes
matrix.node-version in the key. Each Node version gets its own pnpm
store, so the ABI-137 better-sqlite3 binary cached from a Node 24 job
can no longer be served to Node 20 (needs ABI 115) or Node 22 (needs
ABI 127) jobs.
The pnpm store cache key used by setup-node does not include the Node.js
version, so a cache entry written by a Node 24 job contains an ABI-137
better-sqlite3 binary. When Node 20 (ABI 115) or Node 22 (ABI 127) jobs
restore from the same cache key they get the wrong binary and all
sqlite-runner tests fail with "Module did not self-register".
Adding `pnpm rebuild better-sqlite3` after install re-runs prebuild-install
for the active Node version, downloading the correct prebuilt binary and
overwriting whatever ABI was in the restored cache.
Root cause first appeared after the setup-node v4→v6 and pnpm/action-setup
v4→v6 bumps (May 15, PRs #4857/#4858) reset the cold cache, allowing a
Node 24 binary to poison the shared store entry.
The release/publish workflow's build job uploads the entire workspace
as an artifact for the publish job to download. With node_modules and
build caches included, this monorepo produces ~6.4M files, which OOMs
upload-artifact's Node process at its 4GB heap limit during
enumeration:
FATAL ERROR: Ineffective mark-compacts near heap limit
Allocation failed - JavaScript heap out of memory
Excluding node_modules, .next, .turbo, and .nx cuts the file count by
orders of magnitude. The publish job runs `pnpm install --frozen-lockfile`
after download to restore node_modules deterministically from
pnpm-lock.yaml (carried in the artifact), so the publish step still
runs against exactly the resolved dependency tree the build job used.
Fixes the upload step that hung for 12+ minutes and then OOM'd when
the workflow_dispatch trigger added in #4808 was first exercised.
## Summary
Adds a `workflow_dispatch` trigger to
`.github/workflows/publish-release.yml` so the release/publish workflow
can be manually retriggered against the latest commit on `main`.
This is the escape hatch for the current edge case: a release failed
mid-flight, `main` already has the bumped versions, but nothing was
published and the normal PR-merge trigger can't fire again without a
fresh release PR.
## What this covers
✅ Failures **before** the `Publish to npm` step succeeded:
- Build errors
- Infrastructure blips (runner crash, OIDC token issue, npm registry
hiccup)
- Pre-publish workflow bugs (e.g. the `git config --local` issue fixed
in #4874)
## What this does NOT cover
❌ Failures **after** `Publish to npm` succeeded:
- If npm publish ran but tag push or GitHub Release creation failed,
dispatching this workflow will fail at `Publish to npm` with an `already
published` error.
- The `Check for pre-existing tags` step will also block retries where
the tag was pushed but later steps failed.
For those cases: finish the release by hand using `release-notes.md`
from the merged release PR — manually create the git tag at the publish
commit and create the GitHub Release. Don't dispatch.
Both the in-file YAML comment above `workflow_dispatch:` and the
dispatch form's `scope` input description spell this out so operators
see it before triggering.
## Change
Minimal: 33 insertions, 7 deletions in one workflow file.
- New `workflow_dispatch` trigger with a required `scope` choice input
(`monorepo` | `angular`)
- `if` condition widened to also accept `workflow_dispatch` runs
- Scope-extraction step now uses `inputs.scope` when present, falls back
to the existing PR-branch parsing otherwise
- YAML comment above the trigger documents the coverage limits
The normal PR-merge trigger and the entire downstream publish pipeline
are unchanged.
## Test plan
- [ ] Merge to main
- [ ] Actions → "release / publish" → "Run workflow" → pick scope →
confirm publish proceeds against current main versions
- [ ] Confirm a normal release-PR merge still triggers and behaves
identically
- [ ] Confirm dispatch against a state where npm publish already
succeeded fails fast at "Publish to npm" (does not corrupt anything)