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
403 changes: 341 additions & 62 deletions .atomic/workflows/publish-release.ts

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,14 @@ jobs:
exit 1
fi

# main is versionless: it carries the 0.0.0 development placeholder and the
# real version is materialized only on a tagged "Release X" commit produced by
# scripts/cut-release.ts. Refuse to publish the placeholder if it is ever tagged.
if [ "$version" = "0.0.0" ] || [ "$version" = "0.0.0-dev" ]; then
echo "$PACKAGE_DIR/package.json is at the development placeholder ($version); refusing to publish. Cut a release with: bun run scripts/cut-release.ts <version>" >&2
exit 1
fi

if [ "$RELEASE_TAG" != "$expected_tag" ]; then
echo "Tag $RELEASE_TAG does not match $PACKAGE_DIR/package.json version $version (expected $expected_tag)." >&2
exit 1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ permissions:

on:
push:
branches: [main]
branches: [main, "release/**", "prerelease/**"]
pull_request:
branches: [main]

Expand Down
31 changes: 22 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,21 @@ atomic:

## Releasing

Atomic mirrors pi's tag-driven release flow: bump versions locally, commit, push a `<version>` git tag (no leading `v`, for example `0.8.24` or `0.8.24-alpha.1`), and CI publishes to npm with OIDC provenance and creates the GitHub Release with cross-compiled binaries attached.
Atomic uses a **versionless `main`** release flow (modeled on openai/codex): every `packages/*/package.json` on `main` stays at the `0.0.0` placeholder, and the real version is materialized **only** on a throwaway, off-`main` `Release <version>` commit that is tagged but never merged back. Pushing the `<version>` tag (no leading `v`, for example `0.8.24` or `0.8.24-alpha.1`) triggers CI, which publishes to npm with OIDC provenance (stable `<x.y.z>` → `@latest`, prerelease `<x.y.z>-alpha.N` → `@next`) and creates the GitHub Release with cross-compiled binaries attached. Because `main` carries no version, you can cut a stable release and an ahead-of-stable prerelease line from the same trunk without branch gymnastics.

Cut a release with `scripts/cut-release.ts`, which stamps the version onto the off-`main` tag commit and (with `--push`) pushes only the tag:

```sh
bun run scripts/cut-release.ts 0.8.31 # stable -> @latest
bun run scripts/cut-release.ts 0.9.0-alpha.1 # prerelease -> @next
bun run scripts/cut-release.ts 0.8.31 --base main --push
```

`main` is never advanced; the script creates the release commit in a detached git worktree, tags it, and abandons the worktree (the tag keeps the commit alive).

### Agent publishing requests

If a user asks you to publish the package or create a release/prerelease, run the `publish-release` workflow using your workflow tool.
If a user asks you to publish the package or create a release/prerelease, run the `publish-release` workflow using your workflow tool. That workflow opens a CHANGELOG-only release-notes PR to `main`, then stamps and tags the release off-`main` via `cut-release.ts` — it never bumps the version on `main`. It also accepts an optional `base_ref` input (default `main`) to release from a maintenance/integration branch instead of `main`, and an optional `from_ref` input to cut an **ephemeral** release from any commit/tag/branch: the workflow auto-creates `release/<version>` (or `prerelease/<version>`) from that ref, gates on that branch's CI, cuts and publishes the tag, then deletes the branch (the changelog lives on the tag only; `main` is untouched).

## Docs

Expand Down Expand Up @@ -158,17 +168,20 @@ Use these sections under `## [Unreleased]`:
- **Internal changes (from issues)**: `Fixed foo bar ([#123](https://github.com/earendil-works/pi-mono/issues/123))`
- **External contributions**: `Added feature X ([#456](https://github.com/earendil-works/pi-mono/pull/456) by [@username](https://github.com/username))`

## Bumping Versions
## Versionless main & bumping

`main` is versionless: every `packages/*/package.json` (plus `bun.lock` workspace entries, the `@bastani/atomic-natives` dependency pin, `packages/natives/native/index.js` checks, and the Cargo manifests/lock) stays at the `0.0.0` placeholder. **Do not bump the version on `main`.**

Use the top-level `scripts/bump-version.ts` script to update every `packages/*/package.json` version and package README badge:
`scripts/bump-version.ts` is the low-level stamper that rewrites every versioned manifest. It is invoked by `scripts/cut-release.ts` inside a throwaway worktree to materialize the real version on the tagged release commit. You normally never run it directly against `main`; the only direct use is resetting the placeholder if it ever drifts:

```sh
# Explicit version
bun run scripts/bump-version.ts 0.1.0
bun run scripts/bump-version.ts 0.1.0-alpha.1
```
# stamp a real version onto the off-main tag commit (preferred)
bun run scripts/cut-release.ts 0.1.0
bun run scripts/cut-release.ts 0.1.0-alpha.1

Run `bun install` afterward to refresh `bun.lock`.
# low-level: reset main back to the versionless placeholder
bun run scripts/bump-version.ts 0.0.0 && bun install
```

## CI

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["crates/atomic-natives"]
resolver = "3"

[workspace.package]
version = "0.8.31-alpha.5"
version = "0.0.0"
edition = "2024"
license = "MIT"
authors = ["Bastani"]
Expand Down
18 changes: 8 additions & 10 deletions DEV_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,21 +240,19 @@ Examples import the workspace package `@bastani/workflows`.

## Releasing

Atomic uses a tag-driven release flow: push a `<version>` git tag (no leading `v`, for example `0.8.24` or `0.8.24-alpha.1`) and CI cross-compiles binaries, publishes to npm with OIDC provenance, and creates the GitHub Release with binaries attached.
Atomic uses a **versionless `main`** release flow: `main` stays at the `0.0.0` placeholder and the real version is materialized only on a throwaway, off-`main` `Release <version>` commit that is tagged but never merged. Pushing the `<version>` tag (no leading `v`, for example `0.8.24` or `0.8.24-alpha.1`) makes CI cross-compile binaries, publish to npm with OIDC provenance, and create the GitHub Release with binaries attached.

### Workflow

1. Run `bun run scripts/bump-version.ts <version>` (e.g. `0.8.0` or `0.8.0-alpha.1`), then `bun install`.
2. Move the `[Unreleased]` section in `packages/coding-agent/CHANGELOG.md` to a new `## [<version>] - <YYYY-MM-DD>` section. CI extracts release notes from this section.
3. Run `bun run typecheck`, `cd packages/coding-agent && bun run build`, and `bun run test:all`.
4. Commit `packages/*/package.json`, `packages/*/README.md`, `packages/coding-agent/CHANGELOG.md`, and `bun.lock` with `chore(release): bump to <version>`.
5. Tag and push:
1. Land the CHANGELOG move on `main` like any other change: move the `[Unreleased]` section in `packages/coding-agent/CHANGELOG.md` into a new `## [<version>] - <YYYY-MM-DD>` section (CI extracts release notes from it). **Do not bump any `package.json` version** — `main` is versionless.
2. From a clean `main`, cut the release. This stamps the version onto an off-`main` `Release <version>` commit, tags it, and pushes only the tag:
```sh
git tag <version>
git push origin main
git push origin <version>
bun run scripts/cut-release.ts <version> --base main --push
```
6. The tag push triggers `.github/workflows/publish.yml`, which publishes `@bastani/atomic` to npm with OIDC provenance and creates the GitHub Release with six binary archives attached (darwin/linux/windows × arm64/x64).
`main` is never advanced; the script does the stamp in a detached git worktree and abandons it (the tag keeps the commit alive). Omit `--push` to inspect the tag locally first, then `git push origin <version>`.
3. The tag push triggers `.github/workflows/publish.yml`, which builds from the tagged (real-version) commit and publishes `@bastani/atomic` to npm with OIDC provenance — stable `<x.y.z>` → `@latest`, prerelease `<x.y.z>-alpha.N` → `@next` — and creates the GitHub Release with six binary archives attached (darwin/linux/windows × arm64/x64).

To run the full guarded automation (release-notes PR + cut-release + publish monitoring), use the `publish-release` Atomic workflow instead of the manual steps above.

Bun is the development/test/runtime path. **npm is still the registry publication tool** because npm's provenance flow signs the published tarball via OIDC. Provenance is enabled in CI; no `NPM_TOKEN` is needed.

Expand Down
20 changes: 10 additions & 10 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 15 additions & 26 deletions docs/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,18 @@ The publish pipeline (`publish.yml`) runs when:
| `<major>.<minor>.<patch>` (e.g. `0.8.0`) | `latest` | normal release, marked latest |
| `<major>.<minor>.<patch>-<prerelease>` (e.g. `0.8.0-alpha.1`) | `next` | prerelease, not marked latest |

The tag must match `packages/coding-agent/package.json` exactly (no leading `v`). All `packages/*` package versions stay in sync via `scripts/bump-version.ts`.
`main` is **versionless**: every `packages/*/package.json` on `main` sits at the `0.0.0` placeholder. The real version exists only on the tagged, off-`main` `Release <version>` commit produced by `scripts/cut-release.ts`, where the tag matches `packages/coding-agent/package.json` exactly (no leading `v`) and all `packages/*` versions are stamped in sync. publish.yml checks out that tagged commit, so its `validate tag matches package.json` gate sees the real version, not the placeholder. The pipeline also refuses to publish the `0.0.0` placeholder if it is ever tagged directly.

### Version Bump
### Cutting a release (versionless main)

Use the top-level script:
`main` never carries a real version, so releasing does not bump `main`. Instead, `scripts/cut-release.ts` materializes the version on a throwaway, off-`main` `Release <version>` commit and tags it:

```sh
bun run scripts/bump-version.ts 0.8.0
bun run scripts/bump-version.ts 0.8.0-alpha.1
bun install
bun run scripts/cut-release.ts 0.8.0 --base main --push
bun run scripts/cut-release.ts 0.8.0-alpha.1 --base main --push
```

The script updates every `packages/*/package.json` version and any package README version badge. Run `bun install` afterward so `bun.lock` records the same workspace versions.
Internally the script validates a clean tree, creates a detached `git worktree` at the base commit, stamps every versioned manifest with `scripts/bump-version.ts` (all `packages/*/package.json`, the `@bastani/atomic-natives` pin, `packages/natives/native/index.js`, and the Cargo manifests/lock), commits `Release <version>`, tags it, removes the worktree, and pushes only the tag. `main` is never advanced and the tag's commit is the only place the real version lives. `bun.lock` keeps `main`'s `0.0.0` workspace placeholders — it is not shipped in the npm tarball and `bun install --frozen-lockfile` tolerates the version-string mismatch.

### Publish Flow

Expand Down Expand Up @@ -282,16 +281,9 @@ The meaningful pre-publish checks are:

## Release Checklist

1. Bump versions on `main` (or a short-lived PR branch):
1. Move the `[Unreleased]` section in `packages/coding-agent/CHANGELOG.md` to `## [0.8.0] - <YYYY-MM-DD>` and land it on `main` like any normal change. The publish workflow uses this section as the GitHub Release body. **Do not bump any `package.json` version — `main` is versionless.**

```sh
bun run scripts/bump-version.ts 0.8.0
bun install
```

2. Move the `[Unreleased]` section in `packages/coding-agent/CHANGELOG.md` to `## [0.8.0] - <YYYY-MM-DD>`. The publish workflow uses this section as the GitHub Release body.

3. Run local validation:
2. Run local validation (optional; CI repeats it from the tagged commit):

```sh
bun run typecheck
Expand Down Expand Up @@ -321,19 +313,16 @@ The meaningful pre-publish checks are:
rm -rf "$tmpdir"
```

On Windows, substitute `--platform windows-x64`, extract `atomic-windows-x64.zip`, and run `atomic.exe --version` plus the equivalent `atomic.exe --no-session` smoke.
On Windows, substitute `--platform windows-x64`, extract `atomic-windows-x64.zip`, and run `atomic.exe --version` plus the equivalent `atomic.exe --no-session` smoke. (A `main` build reports the `0.0.0` placeholder for `--version`; a release build from the tag reports the real version.)

4. Commit and tag:
3. From a clean `main`, cut and push the release tag. This stamps the version onto an off-`main` `Release 0.8.0` commit, tags it, and pushes only the tag (the publish trigger):

```sh
git add packages/*/package.json packages/coding-agent/CHANGELOG.md bun.lock
git add packages/*/README.md # only if the version bump script changed README badges
git commit -m "chore(release): bump to 0.8.0"
git tag 0.8.0
git push origin main
git push origin 0.8.0
bun run scripts/cut-release.ts 0.8.0 --base main --push
```

5. Confirm `publish.yml` runs docs link validation plus Mintlify syntax and broken-link checks, cross-compiles binaries, publishes `@bastani/atomic-natives` and `@bastani/atomic` to npm with OIDC provenance, and creates the GitHub Release with binaries attached.
Omit `--push` to inspect the tag locally first (`git show 0.8.0`, `git log --oneline -1 0.8.0`), then `git push origin 0.8.0`. `main` is never advanced.

4. Confirm `publish.yml` checks out the tag, runs docs link validation plus Mintlify syntax and broken-link checks, cross-compiles binaries, publishes `@bastani/atomic-natives` and `@bastani/atomic` to npm with OIDC provenance, and creates the GitHub Release with binaries attached.

For prereleases, substitute `0.8.0-alpha.1` and tag `0.8.0-alpha.1`.
For prereleases, substitute `0.8.0-alpha.1`. To run the fully guarded automation (release-notes PR + cut-release + publish monitoring) instead of these manual steps, use the `publish-release` Atomic workflow.
1 change: 1 addition & 0 deletions packages/coding-agent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Bumped the bundled upstream pi runtime libraries `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui` from `^0.79.6` to `^0.79.7` so Atomic inherits upstream v0.79.7 TUI color-scheme, Warp image, generated model catalog, and agent-core fixes.
- Reserved `/` in theme names for automatic light/dark theme settings.
- Replaced the bundled `browser` skill / `browse` CLI with the `playwright-cli` skill and `playwright-cli` command across `@bastani/atomic`, and bundled the new `effective-liteparse` document-extraction skill. The builtin `ralph`, `goal`, and `open-claude-design` workflows and the `debugger`/`codebase-online-researcher` subagents now drive browsers via `playwright-cli`; `open-claude-design`'s deterministic setup step ensures `playwright-cli` (`npm install -g @playwright/cli@latest`) and renames its `browse_cli_status` output to `playwright_cli_status`; and `ralph` now records a `playwright-cli` QA end-to-end proof video (`qa_video_path`) for UI-applicable/full-stack changes, references it in the implementation notes, and attaches or links it to the final pull request when `create_pr=true`. Updated the user-facing docs (workflows, SDK bash-policy examples, quickstart skills, README) to match.
- Switched the repository to a **versionless `main`** release model (modeled on openai/codex): every `packages/*/package.json` on `main` now stays at the `0.0.0` placeholder, and the real version is materialized only on a throwaway, off-`main` `Release <version>` commit created and tagged by the new top-level `scripts/cut-release.ts` (which stamps the version inside a detached git worktree via `scripts/bump-version.ts` and pushes only the tag — `main` is never bumped). This lets a stable release and an ahead-of-stable prerelease line be cut from the same trunk without release branches, mirroring how the npm `@latest`/`@next` dist-tags are derived from the tag shape. `publish.yml` still builds and publishes from the tagged (real-version) commit and now additionally refuses to publish the `0.0.0` placeholder, and the `publish-release` Atomic workflow now lands a CHANGELOG-only release-notes PR on `main` and then stamps/tags the release off-`main` via `cut-release.ts` instead of merging a version bump into `main`, accepts an optional `base_ref` input (default `main`) so a release can be cut from a maintenance/integration branch, and accepts an optional `from_ref` input that cuts an ephemeral release from any commit/tag/branch (auto-creating a CI-gated `release/<version>`/`prerelease/<version>` branch, cutting the tag off it, then deleting it — the changelog lives on the tag only). CI `test.yml` now also runs on `release/**`/`prerelease/**` pushes so those ephemeral branches are gated. End users installing from npm are unaffected; only local/`main` dev builds report `0.0.0` for `--version`.


### Fixed
Expand Down
4 changes: 2 additions & 2 deletions packages/coding-agent/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bastani/atomic",
"version": "0.8.31-alpha.5",
"version": "0.0.0",
"description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
"type": "module",
"atomicConfig": {
Expand Down Expand Up @@ -68,7 +68,7 @@
"prepublishOnly": "bun run clean && bun run build"
},
"dependencies": {
"@bastani/atomic-natives": "0.8.31-alpha.5",
"@bastani/atomic-natives": "0.0.0",
"@bufbuild/protobuf": "^2.0.0",
"@earendil-works/pi-agent-core": "^0.79.7",
"@earendil-works/pi-ai": "^0.79.7",
Expand Down
4 changes: 2 additions & 2 deletions packages/cursor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bastani/cursor",
"version": "0.8.31-alpha.5",
"version": "0.0.0",
"private": true,
"description": "Experimental first-party Atomic extension for Cursor OAuth, model discovery, and streaming provider registration.",
"contributors": [
Expand Down Expand Up @@ -40,7 +40,7 @@
}
},
"dependencies": {
"@bastani/atomic-natives": "0.8.31-alpha.5",
"@bastani/atomic-natives": "0.0.0",
"@bufbuild/protobuf": "^2.0.0"
}
}
Loading
Loading