Files
owen 47ce998b4e
CI / Build (push) Waiting to run
CI / Test (push) Waiting to run
Release / Test release commit (push) Waiting to run
Release / Build macOS Apple Silicon (push) Blocked by required conditions
Release / Build Linux ARM64 (push) Blocked by required conditions
Release / Build Linux x86_64 (push) Blocked by required conditions
Release / Build Windows x86_64 CLI (push) Blocked by required conditions
Release / Upload GitHub release assets (push) Blocked by required conditions
Release / Publish npm packages (push) Blocked by required conditions
Automate desktop release binaries
2026-06-27 13:27:10 -05:00

512 lines
20 KiB
Markdown

# AGENTS.md
## Release process: build artifacts and create a draft GitHub release
Use this process when preparing a Cassady (`cass`) release. Prefer the GitHub Actions release workflow over local cross-builds so macOS/Linux/Windows assets are built on runners instead of by hand. Always create the GitHub release as a **draft** first; do not publish the final release unless the user explicitly asks.
### 0. Preferred automated release workflow
The release workflow is `.github/workflows/release.yml`. On a pushed `v*` tag it builds and uploads draft GitHub release assets automatically. For an existing tag or to publish the release/npm packages, run it manually:
```sh
gh workflow run release.yml \
--repo owenqwenstarsky/cassady \
-f tag="$TAG" \
-f replace_assets=true \
-f publish_github_release=false \
-f publish_npm=false
```
Set `publish_github_release=true` only when the user explicitly asks to publish the GitHub release. Set `publish_npm=true` only when the user explicitly asks to publish npm packages, and make sure the `NPM_TOKEN` repository secret exists first. The workflow deletes/replaces old release assets, uploads the four current archives/checksums, and publishes npm packages from those runner-built archives.
Keep release notes in `docs/releases/${TAG}.md` when the workflow should apply curated notes. If that file is missing, the workflow falls back to generated placeholder notes.
Use the manual steps below only for local debugging or when the workflow cannot be used.
### 1. Review prior releases for consistency
```sh
git fetch origin --tags
gh release list --repo owenqwenstarsky/cassady --limit 5
gh release view --repo owenqwenstarsky/cassady --json tagName,body --jq '.tagName + "\n\n" + .body'
```
Keep release notes consistent with the existing format:
- Title: `## Cassady vX.Y.Z`
- One short summary paragraph.
- `### Downloads` with four bullets in this order: macOS Apple Silicon, Linux x86_64, Linux ARM64, Windows x86_64.
- Note that macOS/Linux archives contain `cass`, `cassady`, and `cassady-desktop`; the Windows archive contains `cass` and `cassady`; mention SHA-256 files.
- `### Highlights` with concise user-facing bullets.
- Optional `### Upgrade notes` only when compatibility, config, or migration details matter.
- `### Install from source` with a `cargo install --git ... --tag vX.Y.Z` command.
- `### Verification` listing the exact test/build commands used.
### 2. Confirm the version and starting state
```sh
git status --short
VERSION=$(awk -F\" '/^version = / { print $2; exit }' Cargo.toml)
TAG="v${VERSION}"
echo "$TAG"
git log --oneline --decorate -20
```
If the version is wrong, update `Cargo.toml` and `Cargo.lock` first, then commit that change before tagging. Release tags should point at the intended release commit on `main`.
### 3. Run verification before packaging
```sh
cargo +stable test --locked --all-targets
```
### 4. Build all release binaries manually only when needed
The runner workflow should normally do this. Manual prerequisites for cross-builds are stable Rust, `cargo-zigbuild`, Tauri CLI, Zig, Node/npm, and the needed Rust targets.
```sh
rustup target add aarch64-apple-darwin x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu x86_64-pc-windows-gnu
cargo install cargo-zigbuild tauri-cli --locked
```
Build the same four CLI targets used by previous releases, then build desktop binaries for macOS/Linux. Do not build or upload DMG/installer artifacts unless the user explicitly asks.
```sh
cargo +stable build --release --locked --target aarch64-apple-darwin
cargo +stable zigbuild --release --locked --target x86_64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target aarch64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target x86_64-pc-windows-gnu
(cd cassady-desktop && cargo tauri build --target aarch64-apple-darwin)
# Build Linux desktop binaries with `cargo tauri build` on Linux/Tauri builders. The packaging step accepts either:
# target/x86_64-unknown-linux-gnu/release/cassady-desktop
# target/aarch64-unknown-linux-gnu/release/cassady-desktop
# or the Tauri builder output paths:
# target/tauri-linux-x86_64/release/cassady-desktop
# target/tauri-linux-aarch64/release/cassady-desktop
```
### 5. Rebuild the `dist/` artifacts
This creates the unpacked artifact directories, compressed archives, and checksum files for the current `$TAG`. Generate checksums from inside `dist/` so the `.sha256` files contain archive names without a `dist/` prefix.
```sh
VERSION=$(awk -F\" '/^version = / { print $2; exit }' Cargo.toml)
TAG="v${VERSION}"
rm -rf \
"dist/cassady-${TAG}-aarch64-apple-darwin"* \
"dist/cassady-${TAG}-x86_64-unknown-linux-gnu"* \
"dist/cassady-${TAG}-aarch64-unknown-linux-gnu"* \
"dist/cassady-${TAG}-x86_64-pc-windows-gnu"*
mkdir -p dist
desktop_binary_for() {
case "$1" in
aarch64-apple-darwin)
if [ -f "target/aarch64-apple-darwin/release/cassady-desktop" ]; then
printf '%s\n' "target/aarch64-apple-darwin/release/cassady-desktop"
else
printf '%s\n' "target/release/cassady-desktop"
fi
;;
x86_64-unknown-linux-gnu)
if [ -f "target/x86_64-unknown-linux-gnu/release/cassady-desktop" ]; then
printf '%s\n' "target/x86_64-unknown-linux-gnu/release/cassady-desktop"
else
printf '%s\n' "target/tauri-linux-x86_64/release/cassady-desktop"
fi
;;
aarch64-unknown-linux-gnu)
if [ -f "target/aarch64-unknown-linux-gnu/release/cassady-desktop" ]; then
printf '%s\n' "target/aarch64-unknown-linux-gnu/release/cassady-desktop"
else
printf '%s\n' "target/tauri-linux-aarch64/release/cassady-desktop"
fi
;;
esac
}
for target in aarch64-apple-darwin x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
name="cassady-${TAG}-${target}"
desktop_bin=$(desktop_binary_for "$target")
test -f "$desktop_bin"
mkdir -p "dist/${name}"
cp "target/${target}/release/cass" "dist/${name}/cass"
cp "target/${target}/release/cassady" "dist/${name}/cassady"
cp "$desktop_bin" "dist/${name}/cassady-desktop"
cp README.md "dist/${name}/README.md"
tar -C dist -czf "dist/${name}.tar.gz" "${name}"
done
win_target=x86_64-pc-windows-gnu
win_name="cassady-${TAG}-${win_target}"
mkdir -p "dist/${win_name}"
cp "target/${win_target}/release/cass.exe" "dist/${win_name}/cass.exe"
cp "target/${win_target}/release/cassady.exe" "dist/${win_name}/cassady.exe"
cp README.md "dist/${win_name}/README.md"
(cd dist && zip -qr "${win_name}.zip" "${win_name}")
(cd dist && for artifact in cassady-${TAG}-*.tar.gz cassady-${TAG}-*.zip; do
shasum -a 256 "$artifact" > "${artifact}.sha256"
done)
```
Sanity-check the generated artifacts:
```sh
ls -lh dist/cassady-${TAG}-*.tar.gz dist/cassady-${TAG}-*.zip dist/cassady-${TAG}-*.sha256
for sum in dist/cassady-${TAG}-*.sha256; do (cd dist && shasum -a 256 -c "$(basename "$sum")"); done
tar -tzf "dist/cassady-${TAG}-aarch64-apple-darwin.tar.gz" | head
tar -tzf "dist/cassady-${TAG}-x86_64-unknown-linux-gnu.tar.gz" | grep cassady-desktop
unzip -l "dist/cassady-${TAG}-x86_64-pc-windows-gnu.zip" | head
```
### 6. Write the release notes
Create `dist/RELEASE_NOTES_${TAG}.md` using the same structure as prior releases. Use this template and replace the summary/highlights with the actual changes:
````md
## Cassady vX.Y.Z
Cassady vX.Y.Z ...
### Downloads
- macOS Apple Silicon: `cassady-vX.Y.Z-aarch64-apple-darwin.tar.gz`
- Linux x86_64: `cassady-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gz`
- Linux ARM64: `cassady-vX.Y.Z-aarch64-unknown-linux-gnu.tar.gz`
- Windows x86_64: `cassady-vX.Y.Z-x86_64-pc-windows-gnu.zip`
The macOS and Linux archives contain `cass`, `cassady`, and `cassady-desktop`; launch the desktop app with `cass desktop`. The Windows archive contains `cass` and `cassady`. SHA-256 checksum files are included for every archive.
### Highlights
- ...
### Upgrade notes
...
### Install from source
```sh
cargo install --git https://github.com/owenqwenstarsky/cassady --tag vX.Y.Z
```
### Verification
Built and tested with:
```sh
cargo +stable test --locked --all-targets
cargo +stable build --release --locked --target aarch64-apple-darwin
cargo +stable zigbuild --release --locked --target x86_64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target aarch64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target x86_64-pc-windows-gnu
(cd cassady-desktop && cargo tauri build --target aarch64-apple-darwin)
# Linux desktop binaries built with `cargo tauri build` on Linux/Tauri builders and copied into the Linux archives.
```
````
Check the notes before uploading:
```sh
sed -n '1,220p' "dist/RELEASE_NOTES_${TAG}.md"
```
### 7. Tag the release commit
Only tag after tests pass, artifacts are built, and release notes are ready.
```sh
git fetch origin --tags
git status --short # should be clean except generated dist/ files
git tag -a "$TAG" -m "Cassady ${TAG}"
git push origin "$TAG"
```
If the tag already exists, stop and ask before deleting or moving it.
### 8. Create the GitHub release as a draft
Upload only the current version's archives and checksum files. Keep `--draft` and `--verify-tag` in the command.
```sh
gh release create "$TAG" \
"dist/cassady-${TAG}-aarch64-apple-darwin.tar.gz" \
"dist/cassady-${TAG}-aarch64-apple-darwin.tar.gz.sha256" \
"dist/cassady-${TAG}-x86_64-unknown-linux-gnu.tar.gz" \
"dist/cassady-${TAG}-x86_64-unknown-linux-gnu.tar.gz.sha256" \
"dist/cassady-${TAG}-aarch64-unknown-linux-gnu.tar.gz" \
"dist/cassady-${TAG}-aarch64-unknown-linux-gnu.tar.gz.sha256" \
"dist/cassady-${TAG}-x86_64-pc-windows-gnu.zip" \
"dist/cassady-${TAG}-x86_64-pc-windows-gnu.zip.sha256" \
--repo owenqwenstarsky/cassady \
--title "Cassady ${TAG}" \
--notes-file "dist/RELEASE_NOTES_${TAG}.md" \
--draft \
--verify-tag
```
Verify the draft:
```sh
gh release view "$TAG" --repo owenqwenstarsky/cassady --json tagName,name,isDraft,isPrerelease,assets --jq .
```
Do **not** publish the draft or mark it as the final/latest release unless the user explicitly asks.
## NPM package process: prepare and publish the binary packages
Use this process when preparing Cassady for npm. The npm distribution is a tiny wrapper package plus platform-specific binary packages. Do not publish to npm unless the user explicitly asks; when they ask for a publish-ready setup, make sure the packages can be published with one command.
### Package layout and names
The committed npm tooling generates packages under `dist/npm/` from the current Rust version in `Cargo.toml`:
- Wrapper package: `cassady`
- Exposes both npm binaries: `cass` and `cassady`.
- `cass desktop` launches the bundled desktop binary when the installed platform package includes one.
- Depends on the platform packages through `optionalDependencies` at the exact same version.
- Platform packages:
- `@cassady/cli-darwin-arm64` for `aarch64-apple-darwin`
- `@cassady/cli-linux-x64` for `x86_64-unknown-linux-gnu`
- `@cassady/cli-linux-arm64` for `aarch64-unknown-linux-gnu`
- `@cassady/cli-win32-x64` for `x86_64-pc-windows-gnu`
Before the first publish, make sure the npm account owns or has publish access to the `cassady` package name and the `@cassady` scope. If the npm package name or scope changes, update `npm/scripts/lib/release-config.mjs` and regenerate the packages. Scoped packages are published with `--access public`.
### 1. Build the release binaries first
Prefer the `.github/workflows/release.yml` workflow with `publish_npm=true`; it rebuilds release assets on runners, rehydrates the npm package inputs from those archives, and publishes with `NPM_TOKEN`. For manual publishing, the npm packages copy binaries from the release build outputs, so run the same verification and target builds used for the GitHub release first. macOS/Linux packages include `cassady-desktop` so `cass desktop` works from npm installs; Windows remains CLI-only for now.
```sh
cargo +stable test --locked --all-targets
cargo +stable build --release --locked --target aarch64-apple-darwin
cargo +stable zigbuild --release --locked --target x86_64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target aarch64-unknown-linux-gnu
cargo +stable zigbuild --release --locked --target x86_64-pc-windows-gnu
(cd cassady-desktop && cargo tauri build --target aarch64-apple-darwin)
# Linux desktop binaries built with `cargo tauri build` on Linux/Tauri builders, as in the GitHub release process.
```
### 2. Generate and verify the npm package directories
```sh
npm run npm:prepare
npm run npm:verify
```
`npm:prepare` rebuilds `dist/npm/` for the current `Cargo.toml` version. `npm:verify` runs `npm publish --dry-run` for each generated package and does not publish anything.
### 3. Publish to npm when explicitly requested
The publish command prepares packages, checks npm auth, runs `npm login` if needed, checks whether each package version already exists, publishes platform packages first, publishes the wrapper last, and verifies that the published versions can be packed from npm. The existence/verification checks intentionally use `npm pack --dry-run` instead of `npm view` because npm registry metadata for newly-created scoped packages can briefly return 404 even after publish succeeds.
```sh
npm run npm:publish
```
Optional checks and controls:
```sh
npm run npm:publish -- --dry-run # full publish flow without publishing
NPM_TAG=next npm run npm:publish # publish under a non-latest dist-tag
```
If a version already exists, npm cannot overwrite it. Stop and ask before changing versions, deleting packages, or moving dist-tags.
## Roadmap process: write a new release entry in `ROADMAP.md`
Use this process when planning a future Cassady release. Follow the existing newest-first format in `ROADMAP.md` so new entries look like prior releases.
### 1. Review the existing roadmap format
```sh
sed -n '1,220p' ROADMAP.md
ls plans
```
Current conventions:
- Keep the `# Cassady (Cass) Roadmap` title at the top.
- Add the newest release immediately below the title, above older releases.
- Use headings like `## vX.Y.Z — Short Theme` for planned releases.
- Add `✅ Completed` to the heading only after the release is actually complete.
- Start with a short paragraph: `This release focuses on ...`.
- If there is a detailed plan, reference it with a sentence like: See `plans/PLAN_FILE.md`.
- Group work under `###` area headings such as `Interactive Setup`, `Agent Control`, or `Safety and Reviewability`.
- Use checklist items: `- [ ]` for planned work, `- [x]` for completed work.
- Write main tasks as bold, user-facing outcomes: `**Add a first-run setup wizard.** ...`.
- Use indented bullets for scope details, constraints, and explicit deferrals.
### 2. Decide the release scope
Before editing `ROADMAP.md`, identify:
- Version number: `vX.Y.Z`.
- Short theme: a concise release name after the em dash.
- One-paragraph goal: what the release changes for users.
- 2-4 major areas to group the work.
- Concrete checklist tasks under each area.
- Any intentionally deferred work, especially broad integrations or risky scope.
- Optional plan file under `plans/` if the release needs deeper implementation detail.
Prefer roadmap items that describe outcomes and acceptance criteria, not implementation minutiae. Keep them concise enough to scan.
### 3. Insert the new entry
Place the new release section directly under the top-level title:
```md
# Cassady (Cass) Roadmap
## vX.Y.Z — Short Release Theme
This release focuses on ... See `plans/VX_Y_Z_SHORT_PLAN.md`.
### Area Name
- [ ] **User-facing task title.** Describe the outcome in one sentence.
- Add key behavior or acceptance criteria.
- Note constraints or non-goals.
- [ ] **Second task title.** Describe the next outcome.
- Include compatibility, docs, tests, or safety requirements when relevant.
### Another Area
- [ ] **Another task title.** Describe the outcome.
- Keep details specific and checkable.
## vPrevious — Existing Theme ✅ Completed
```
If there is no detailed plan file yet, omit the `See ...` sentence rather than linking to a nonexistent file.
### 4. Keep old entries stable
- Do not reorder completed releases except to insert the new release at the top.
- Do not rewrite old completed scopes unless correcting a clear error.
- Use `[x]` only for work that has landed.
- Add `✅ Completed` only when the release has shipped or the user explicitly asks to mark it complete.
- Keep wording consistent with earlier entries: concise headings, bold task names, and nested details.
### 5. Check the edit
```sh
sed -n '1,180p' ROADMAP.md
git diff -- ROADMAP.md
```
## Plan process: write implementation plans in `plans/`
Use this process when creating or updating an implementation plan. All project plans belong in the `plans/` directory; do not put new plan documents at the repository root.
### 1. Review previous plans first
```sh
ls plans
sed -n '1,240p' plans/V0_2_2_ONBOARDING_SETUP_WIZARD_PLAN.md
sed -n '1,220p' plans/V0_2_1_MESSAGE_RENDERING_POLISH_PLAN.md
sed -n '1,220p' plans/V0_2_1_COLLAPSED_TOOL_DENSITY_PLAN.md
```
Also read any plan that is directly related to the new work. For example, read `plans/SECURITY_ACCESS_MODES_PLAN.md` before planning access-control work, or `plans/PROVIDER_MODEL_CONFIG_PLAN.md` before planning provider/config changes.
### 2. Choose the plan filename
Write new plans under `plans/` using uppercase snake-case names:
- Release-scoped plan: `plans/VX_Y_Z_SHORT_THEME_PLAN.md`, e.g. `plans/V0_2_3_CONTEXT_MANAGEMENT_PLAN.md`.
- Feature/follow-up plan: `plans/FEATURE_OR_AREA_PLAN.md`, e.g. `plans/SECURITY_ACCESS_MODES_PLAN.md`.
- Follow-up to an existing release plan: include the version and specific topic, e.g. `plans/V0_2_1_COLLAPSED_TOOL_DENSITY_PLAN.md`.
Prefer one focused plan per coherent feature or release theme. Do not edit `plans/PLAN.md` for new release work; it is the historical MVP plan.
### 3. Match the existing plan structure
Most plans should use this shape, adapted to the task size:
````md
# vX.Y.Z Short Theme Implementation Plan
## Goal
State the user-facing outcome in a short paragraph. If helpful, add a success statement.
## Scope
### In scope
- Concrete included work.
- Supported behavior and user-visible changes.
### Out of scope
- Explicit non-goals and deferred work.
- Integrations or risky scope that should not be pulled into this plan.
## Context or Current State
Describe the relevant files, modules, existing behavior, and constraints.
## Design Principles
1. Principle that guides tradeoffs.
2. Safety, compatibility, or UX constraint.
3. Simplicity or deferral rule.
## Design
Describe the proposed behavior and architecture. Include tables, examples, CLI output, JSON shapes, or module/type sketches when they make implementation clearer.
## Implementation Steps
1. First concrete code/docs step.
2. Next step.
3. Final integration step.
## Tests
- Specific unit/integration tests to add or update.
- Manual checks when automated tests are not enough.
## Documentation
- README, bundled docs, release notes, or roadmap updates required.
## Acceptance Criteria
- Checkable condition that proves the plan is done.
- `cargo fmt` and `cargo test --locked --all-targets` pass.
````
For small follow-ups, it is okay to use the shorter style from `V0_2_1_COLLAPSED_TOOL_DENSITY_PLAN.md`: `Context`, `Goal`, `Scope`, `Design`, `Implementation Steps`, and `Acceptance Criteria`.
### 4. Writing guidelines
- Keep plans implementation-oriented but readable by a future agent.
- Be explicit about in-scope vs out-of-scope work to prevent scope creep.
- Mention exact files/modules when known, such as `src/ui/render.rs` or `src/config.rs`.
- Include examples of expected CLI output, JSON, or UI text when behavior matters.
- Add compatibility and migration notes when config, storage, provider behavior, or public commands change.
- Add docs and tests sections for any user-facing change.
- Prefer ordered implementation steps over vague tasks.
- Do not mark roadmap items complete just because a plan was written.
### 5. Check the plan
```sh
sed -n '1,260p' plans/YOUR_PLAN_FILE.md
git diff -- plans/YOUR_PLAN_FILE.md ROADMAP.md
```
## General project notes
- This is a Rust project. Use `cargo test --locked --all-targets` before handing off code changes when practical.
- Keep release notes user-facing and concise; avoid dumping raw commit logs.
- `dist/` contains generated release artifacts. Rebuild current-version files rather than editing archives by hand.