Skip to content

Commit 84e8605

Browse files
authored
refactor(registry): unify package build/publish lifecycle in agentos-toolchain (#222)
1 parent 73051e0 commit 84e8605

78 files changed

Lines changed: 1682 additions & 1051 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: publish-registry
3+
description: Publish @agentos-software/* registry packages (per-package semver; dist-tag dev by default, latest only deliberately). Use whenever the user asks to publish or release registry software/agent packages.
4+
---
5+
6+
# Publish registry packages
7+
8+
Registry packages version **independently** (per-package semver in each
9+
`package.json`). Publishing never moves `latest` unless asked. Full lifecycle
10+
reference: `registry/README.md`.
11+
12+
1. **Build** (skip what's already built):
13+
14+
```bash
15+
just registry-native # native wasm binaries, once per checkout (slow)
16+
just registry-build [pkg] # stage bin/ + assemble dist/package
17+
just registry-status --remote # local state vs published dist-tags
18+
```
19+
20+
2. **Bump the version** in `registry/software/<pkg>/package.json` (or
21+
`registry/agent/<pkg>/`) and commit it.
22+
23+
3. **Publish**:
24+
25+
```bash
26+
just registry-publish <pkg> # dist-tag dev (safe default)
27+
just registry-publish <pkg> latest # DELIBERATE release — moves latest
28+
just registry-publish-all [tag] # every built software package
29+
```
30+
31+
Notes:
32+
- secure-exec **previews** (publish.yaml, no version input) automatically
33+
include all registry packages under the branch dist-tag — no manual step for
34+
preview consumers.
35+
- agent-os pins per-package: `just agentos-pkgs-update [tag]` /
36+
`just agentos-pkgs-set-version <pkg> <v>` over there.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
name: release-preview
3+
description: Cut a secure-exec release-preview — npm-only branch-dist-tag publish (registry packages included), no crates.io. Use when the user asks for a preview / release-preview of secure-exec, or to hand a build to a downstream.
4+
---
5+
6+
# Release-preview secure-exec
7+
8+
A preview publishes the `@secure-exec/*` packages AND the `@agentos-software/*`
9+
registry packages to npm under the sanitized branch dist-tag, versioned
10+
`0.0.0-<branch>.<sha>`, from a fast debug build. No crates.io publish (it has
11+
no preview track — crate changes reach downstreams via their clone-at-sha
12+
builds), no git tag, no release assets.
13+
14+
1. **Push the branch** you want previewed (jj colocated; use
15+
`jj --config snapshot.max-new-file-size=16777216 ...` if large assets
16+
complain).
17+
18+
2. **Dispatch + watch**:
19+
20+
```bash
21+
just release-preview <branch>
22+
run=$(gh run list -R rivet-dev/secure-exec --workflow=publish.yaml -L1 --json databaseId --jq '.[0].databaseId')
23+
gh run watch -R rivet-dev/secure-exec "$run" --exit-status
24+
```
25+
26+
3. **Consume**: `npm install @secure-exec/core@<sanitized-branch>` (same tag for
27+
the registry packages). agent-os does NOT normally consume these directly —
28+
it pins a sha in `.github/refs/secure-exec` and its own release-preview
29+
auto-cuts the matching secure-exec preview (branch `agentos-dep-<sha7>`).
30+
31+
Notes:
32+
- Release-preview is for previews ONLY; never cut a release with it — releases
33+
go through the `release` skill.
34+
- On failure: `gh run view <run> --log-failed`, fix, re-dispatch, re-watch.

.claude/skills/release/SKILL.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
name: release
3+
description: Cut a stable secure-exec release — npm + crates.io in lockstep, plus the manual @secure-exec/core wasm publish. Use whenever the user asks to release secure-exec (a real version, not a preview).
4+
---
5+
6+
# Release secure-exec (stable)
7+
8+
Releases publish the `@secure-exec/*` npm packages AND the `secure-exec-*`
9+
crates at the SAME version. Previews are a different flow (npm-only branch
10+
dist-tag; see CLAUDE.md "Preview-publishing").
11+
12+
1. **Cut the release** from a clean, pushed main checkout:
13+
14+
```bash
15+
just release --patch -y # or --minor / --major / --version <v>; -rc. versions get the rc tag
16+
```
17+
18+
This bumps versions, commits, pushes, and dispatches `publish.yaml` with the
19+
version input → release build: npm `@latest`, crates.io, GitHub release assets.
20+
21+
2. **Watch it green**:
22+
23+
```bash
24+
run=$(gh run list -R rivet-dev/secure-exec --workflow=publish.yaml -L1 --json databaseId --jq '.[0].databaseId')
25+
gh run watch -R rivet-dev/secure-exec "$run" --exit-status
26+
```
27+
28+
3. **Manual step — `@secure-exec/core`** (CI-excluded; its tarball vendors the
29+
wasm commands and CI does not build them):
30+
31+
```bash
32+
make -C registry/native wasm
33+
cd packages/core && npm publish # npm, NOT pnpm; same version CI used; prepack fails loud if commands absent
34+
```
35+
36+
4. **Registry packages are NOT part of a release** — they version per-package;
37+
use the `publish-registry` skill.
38+
39+
5. Downstream: an agent-os release passes this version via
40+
`just release --secure-exec-version <v>` (agent-os `release-agentos` skill).

.github/workflows/publish.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ jobs:
243243
pnpm --dir packages/core run copy-commands
244244
test -f packages/core/commands/sh
245245
- name: Bump package versions for build
246+
env:
247+
# Previews publish the registry packages under the branch dist-tag too.
248+
PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }}
246249
run: |
247250
pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \
248251
--version ${{ needs.context.outputs.version }} \
@@ -253,12 +256,15 @@ jobs:
253256
--filter='!./examples/*' \
254257
--filter='!@secure-exec/website'
255258
- name: Finalize package versions for publish
259+
env:
260+
PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }}
256261
run: |
257262
pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \
258263
--version ${{ needs.context.outputs.version }}
259264
- name: Publish npm packages
260265
env:
261266
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
267+
PUBLISH_INCLUDE_REGISTRY_PACKAGES: ${{ needs.context.outputs.trigger != 'release' && '1' || '' }}
262268
run: |
263269
pnpm --filter=publish exec tsx src/ci/bin.ts publish-npm \
264270
--tag ${{ needs.context.outputs.npm_tag }} \

CLAUDE.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ Every bound that protects a shared resource — memory/heap, CPU/wall-clock, fd/
8282
- JavaScript host-emulation config (`CreateVmConfig.jsRuntime`) mirrors esbuild's vocabulary so users carry over a known mental model. The host environment presented to guest JS is a `platform`; its values are esbuild's exactly — `node` | `browser` | `neutral` — plus the one sanctioned extension `bare` (language-only: ECMAScript spec globals + WebAssembly, nothing host-provided), for which esbuild has no equivalent. Do not invent other platform names. Wherever a JS runtime/resolution config property has an esbuild equivalent, take esbuild's name and value spelling over any other source (esbuild > tsconfig > ad-hoc); introduce a non-esbuild name only when esbuild has no equivalent concept (e.g. `moduleResolution`, `allowedBuiltins`).
8383
- `packages/core/` is `@secure-exec/core`, the generic TypeScript protocol, client, descriptor, and runtime asset package.
8484
- `packages/build-tools/` is `@secure-exec/build-tools`, the workspace-only generator package for V8 bridge and base filesystem assets. A fresh checkout must run `pnpm install` before any `cargo` build (including when a downstream like agent-os path-deps these crates): `v8-runtime/build.rs` generates the V8 bridge assets from `packages/build-tools/node_modules` and panics if they are absent.
85-
- Registry software, filesystem, and tool packages live under `registry/` with the `@secure-exec/*` npm scope.
85+
- Registry software and agent packages live under `registry/` with the `@agentos-software/*` npm scope (tool packages keep `@secure-exec/*`). Their build/publish lifecycle is owned by `@rivet-dev/agentos-toolchain` (`packages/agentos-toolchain`: `stage`/`build`/`pack`/`publish`) driven by the `just registry-*` recipes; the full flow is documented in `registry/README.md`. Never add package-local copy scripts or Makefile staging — declare commands/aliases/stubs in the package's `agentos-package.json` and let `stage` populate the gitignored `bin/`.
8686

8787
## Build And Assets
8888

8989
- The VM base filesystem artifact is derived from Alpine Linux, but runtime source should stay generic.
9090
- Rebuild the base filesystem (requires Docker) with `pnpm --dir packages/build-tools build:base-filesystem`. The one script snapshots Alpine, applies the secure-exec transforms, and writes the single canonical `packages/core/fixtures/base-filesystem.json`, mirroring the same bytes into the crate-vendored `crates/sidecar/assets/` and `crates/vfs/assets/` copies (those exist only as the `cargo publish` fallback; never hand-edit them).
9191
- The V8 bridge bundle is generated from `packages/build-tools/scripts/build-v8-bridge.mjs`; keep its generated assets aligned with bridge-contract changes.
92-
- `registry/native` owns the Rust-to-WASM command build; package-local `registry/software/*/wasm/` output is release material.
92+
- `registry/native` owns the Rust-to-WASM command build (`just registry-native`, or `just registry-native-cmd <name>` for one `cmd-<name>` crate); its `target/wasm32-wasip1/release/commands/` output feeds `agentos-toolchain stage`, which populates each package's gitignored `bin/` for `agentos-toolchain build` to assemble into `dist/package/`.
9393

9494
## npm Compatibility
9595

@@ -110,13 +110,13 @@ Every bound that protects a shared resource — memory/heap, CPU/wall-clock, fd/
110110

111111
### Release Tracks
112112

113-
- **secure-exec runtime**`@secure-exec/*` npm packages and `secure-exec-*` crates; releases keep npm/crates in sync, previews are npm-only. See "Preview-publishing" and "Publishing" for details.
113+
- **secure-exec runtime**`@secure-exec/*` npm packages and `secure-exec-*` crates; releases keep npm/crates in sync, previews are npm-only. See "Release-previewing" and "Publishing" for details.
114114
- **`@agentos-software/*` registry packages** — generic VM software from secure-exec `registry/software/*` plus agent adapters from secure-exec `registry/agent/*`; versioned independently of secure-exec runtime packages.
115115
- **agent-os product/API**`@rivet-dev/agentos*`, AgentOs APIs, sidecar wrapper, docs, quickstarts, and examples; see agent-os `CLAUDE.md` for its pinning workflow.
116116

117-
### Preview-publishing
117+
### Release-previewing
118118

119-
Dispatch `.github/workflows/publish.yaml` (workflow_dispatch) with no version input to cut a **preview** (debug sidecar build, npm-only, dist-tag = sanitized branch name) — for handing a build to a downstream (agent-os) or external project. **Preview-publish is for previews ONLY; never cut a release with it.** Caveats: WASM-bearing packages (`@secure-exec/core`, `@agentos-software/*`) publish MANUALLY (see Publishing), and the crates.io job is skipped on preview — a *crate* change only reaches consumers locally (path dep / `[patch]`) or via a real release.
119+
`just release-preview <branch>` dispatches `.github/workflows/publish.yaml` (workflow_dispatch, no version input) to cut a **preview** (debug sidecar build, npm-only, dist-tag = sanitized branch name) — for handing a build to a downstream (agent-os) or external project. **Preview-publish is for previews ONLY; never cut a release with it.** Caveats: WASM-bearing packages (`@secure-exec/core`, `@agentos-software/*`) publish MANUALLY (see Publishing), and the crates.io job is skipped on preview — a *crate* change only reaches consumers locally (path dep / `[patch]`) or via a real release.
120120

121121
### Testing a local build from an external project (same machine)
122122

@@ -125,11 +125,16 @@ Dispatch `.github/workflows/publish.yaml` (workflow_dispatch) with no version in
125125

126126
## Publishing
127127

128+
Workflow skills (follow these rather than improvising):
129+
- `.claude/skills/release` — stable release (npm + crates.io lockstep, incl. the manual `@secure-exec/core` wasm publish).
130+
- `.claude/skills/release-preview` — branch preview (`just release-preview <branch>`; npm-only, branch dist-tag, registry packages included).
131+
- `.claude/skills/publish-registry``@agentos-software/*` registry packages (per-package semver, `dev` tag default, `latest` deliberate).
132+
- agent-os side: its `.claude/skills/{bump-secure-exec,release-preview,release}` cover consuming/releasing against secure-exec.
133+
128134
- **The `@secure-exec/*` npm packages and the `secure-exec-*` Cargo crates are always published at the same version** (npm and crates stay in sync), so a downstream pins both to one `<v>`. See "Release Tracks" for how this differs from `@agentos-software/*` and agent-os releases.
129-
- CI (`.github/workflows/publish.yaml`) does NOT build or publish the WASM command binaries. There is no `build-commands` job and nothing restores a `wasm-commands` artifact — the workflow only builds/publishes the sidecar binary and the pure-TS packages.
130-
- WASM-bearing packages are ALWAYS published MANUALLY: `@secure-exec/core` (which vendors `registry/native` commands into `packages/core/commands` via `copy-wasm-commands.mjs`, guarded by its `prepack --require`) and the `@agentos-software/*` registry software. `@secure-exec/core` is in `EXCLUDED` in `scripts/publish/src/lib/packages.ts`, so CI never publishes it.
131-
- Manual core flow: build the commands locally (`make -C registry/native wasm`), then `npm publish` (not `pnpm publish`) `@secure-exec/core` at the **same version** CI used for that release so dependents resolving `@secure-exec/core@<version>` succeed. `prepack` vendors the commands and fails loud if they are absent.
132-
- Rationale: building WASM in CI was slow/flaky and repeatedly shipped tarballs missing the command set (the `wasm/` output is a gitignored build artifact). Keeping the WASM publish manual makes the vendored command set authoritative and avoids empty-package regressions.
135+
- CI (`.github/workflows/publish.yaml`) DOES build and vendor the core WASM command set: the "Build and vendor core WASM commands" step runs `make -C registry/native wasm` + `packages/core run copy-commands` before the npm publish, and core's `prepack` fails loud if the commands are absent — so a published `@secure-exec/core` tarball always carries the command set. (`EXCLUDED` in `scripts/publish/src/lib/packages.ts` contains only the private `publish` package.)
136+
- `@agentos-software/*` registry software releases stay MANUAL and per-package (`just registry-publish <pkg> [tag]`; dist-tag `dev` unless `latest` is passed deliberately); PREVIEWS include them automatically under the branch dist-tag (`PUBLISH_INCLUDE_REGISTRY_PACKAGES`).
137+
- `copy-wasm-commands.mjs` (core's vendoring) is the ONE sanctioned package-local copy script: it vendors the baseline command set into the published `@secure-exec/core` tarball at build/prepack time. Every registry package instead declares commands in `agentos-package.json` and lets `agentos-toolchain stage` populate `bin/`.
133138

134139
## Website
135140

justfile

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,83 @@ docs-verify:
2020
node website/scripts/compare-fixture.mjs
2121
node website/scripts/compare-visual.mjs
2222

23+
# --- Registry (@agentos-software/* packages) -------------------------------
24+
# Full flow + package format: registry/README.md.
25+
26+
# Compile ALL native wasm command binaries (slow; needed once per checkout)
27+
registry-native:
28+
make -C registry/native wasm
29+
30+
# Recompile ONE command binary (cargo package cmd-<CMD>), e.g. `just registry-native-cmd sh`
31+
registry-native-cmd CMD:
32+
make -C registry/native wasm-cmd CMD="{{ CMD }}"
33+
34+
# Build one registry package (stage bin/ + tsc + assemble dist/package), or all when PKG is empty.
35+
# Bootstrap note: on a fresh checkout the `agentos-toolchain` bin symlinks are
36+
# only created by `pnpm install` AFTER the toolchain's dist exists — so prime it.
37+
registry-build PKG="":
38+
#!/usr/bin/env bash
39+
set -euo pipefail
40+
npx turbo build --filter '@rivet-dev/agentos-toolchain' >/dev/null
41+
pnpm install --frozen-lockfile >/dev/null
42+
if [ -n "{{ PKG }}" ]; then
43+
dir=""
44+
for base in registry/software registry/agent; do
45+
[ -d "$base/{{ PKG }}" ] && dir="$base/{{ PKG }}"
46+
done
47+
[ -n "$dir" ] || { echo "ERROR: no registry/software/{{ PKG }} or registry/agent/{{ PKG }}"; exit 1; }
48+
npx turbo build --filter "./$dir"
49+
else
50+
npx turbo build --filter './registry/software/*' --filter './registry/agent/*'
51+
fi
52+
53+
# Run the registry integration tests (registry/tests)
54+
registry-test *args:
55+
pnpm --dir registry test "$@"
56+
57+
# Publish one software/agent package. Dist-tag defaults to `dev`; pass
58+
# TAG=latest ONLY for a deliberate release (it moves the latest pointer).
59+
registry-publish PKG TAG="dev":
60+
#!/usr/bin/env bash
61+
set -euo pipefail
62+
dir=""
63+
for base in registry/software registry/agent; do
64+
[ -d "$base/{{ PKG }}" ] && dir="$base/{{ PKG }}"
65+
done
66+
[ -n "$dir" ] || { echo "ERROR: no registry/software/{{ PKG }} or registry/agent/{{ PKG }}"; exit 1; }
67+
if [ "{{ TAG }}" = "latest" ]; then
68+
node packages/agentos-toolchain/dist/cli.js publish "$dir" --latest
69+
else
70+
node packages/agentos-toolchain/dist/cli.js publish "$dir" --tag "{{ TAG }}"
71+
fi
72+
73+
# Publish ALL built software packages (skips unbuilt ones with a notice)
74+
registry-publish-all TAG="dev":
75+
#!/usr/bin/env bash
76+
set -euo pipefail
77+
for dir in registry/software/*/; do
78+
[ -f "$dir/package.json" ] || continue
79+
if [ ! -f "$dir/dist/index.js" ]; then
80+
echo "SKIP: $dir (not built)"
81+
continue
82+
fi
83+
if [ "{{ TAG }}" = "latest" ]; then
84+
node packages/agentos-toolchain/dist/cli.js publish "$dir" --latest
85+
else
86+
node packages/agentos-toolchain/dist/cli.js publish "$dir" --tag "{{ TAG }}"
87+
fi
88+
done
89+
90+
# Show per-package state (version, staged bin/, assembled dist). --remote adds npm dist-tags.
91+
registry-status *args:
92+
node registry/scripts/status.mjs "$@"
93+
2394
release *args:
2495
pnpm --filter=publish release "$@"
2596

26-
preview-publish REF:
97+
# Cut a release-preview (debug build, npm-only, branch dist-tag; also publishes
98+
# the registry packages under that tag) — see the release-preview skill.
99+
release-preview REF:
27100
gh workflow run .github/workflows/publish.yaml --ref "{{ REF }}"
28101

29102
test-bounded cmd='pnpm test':

0 commit comments

Comments
 (0)