How to push a new release. The GitHub Release flow is automated — you just push a tag and the workflow builds three artifacts and posts them. The npm + Homebrew flow is still manual (intentionally — they need account credentials I shouldn't ever see).
# 1. Bump version in package.json + create the tag.
npm version patch # or: minor / major / 0.3.0
# 2. (Optional) Write release notes:
# docs/RELEASE_v0.X.Y.md (otherwise auto-generated from commits)
# 3. Push the tag → triggers the GitHub Release workflow.
git push --follow-tags
# → the release.yml workflow builds + uploads:
# lisa-source-v0.X.Y.tar.gz
# lisa-mac-bundle-v0.X.Y.zip
# lisa-linux-bundle-v0.X.Y.tar.gz
# SHA256SUMS.txt
# 4. Then publish to npm:
npm publish --access public
# 5. Then bump the Homebrew tap (after npm publish lands):
gh workflow run "Release — Homebrew tap"Total: ~10 minutes per release.
Triggered by git push --follow-tags after npm version. The
release.yml workflow does the work:
- Validates that
package.jsonversion matches the tag. - Runs scripts/build-release.sh to produce three artifacts in
dist-release/:lisa-source-vX.Y.Z.tar.gz— the npm-style tarball (~28 MB). Same content asnpm publishships. For users who want clean source.lisa-mac-bundle-vX.Y.Z.zip— self-contained "drop-and-go" bundle (~80 MB):bin/lisa(CLI shim)bin/lisa-gui.command(Mac users double-click → opens browser to web UI)dist/(compiled JS + 114 mood portraits)node_modules/(runtime deps, no devDependencies)QUICKSTART.txt+ README
lisa-linux-bundle-vX.Y.Z.tar.gz— same as Mac minus the .command launcher.
- Computes SHA-256 checksums (
SHA256SUMS.txt). - If
docs/RELEASE_v<version>.mdexists, uses it as release body; otherwise GitHub auto-generates from commit messages. - Posts the GitHub Release.
User caveat for the Mac/Linux bundles: they still need Node.js 20+
on PATH. The bundles include all npm deps but not Node itself.
Bundling Node would mean a 130-150 MB tarball per platform and
fighting the sharp native dep across architectures — trade-off
deferred.
To trigger manually (e.g. re-build a release):
gh workflow run release.yml -f tag=v0.2.0To run the build locally without pushing:
./scripts/build-release.sh
ls dist-release/# Login to npm with your account.
npm whoami # check who you are
npm login # if neededThe package name is scoped (@oratis/lisa), so npm won't conflict with the global lisa namespace. It also implies the package is publicly published under your scope.
# 1. Bump the version in package.json (semver: bug fix → patch, new feature → minor, breaking → major).
npm version patch # or minor / major / 0.3.0
git push --follow-tags
# 2. Verify the tarball before publishing.
npm pack --dry-run | tail -10 # confirm size + file count look sane
# 3. Publish (this fires `prepublishOnly` first, which:
# - runs `npm run build`
# - replaces dist/web/assets symlink with a real copy of src/web/assets
# so the tarball has the 114 mood portraits inlined).
npm publish --access public
# 4. After publish, npm fires `postpublish` which restores the dev symlink.
# If for some reason it didn't, just run:
npm run copy-assetsfiles field in package.json whitelists:
dist/(compiled JS + d.ts + sourcemaps + bundled web assets)channels.example.jsoncompletions/(bash/zsh/fish)LICENSE,README.md,README.zh-CN.md
Excluded by default (and double-excluded via .npmignore):
src/,scripts/,docs/,website/,reference/node_modules/,.git/, dotfiles, env files
Tarball size: ~30 MB (the bulk is the 114 pixel-art mood portraits; they're what make Lisa visually distinctive, so we bundle them).
npm i -g @oratis/lisa
lisa --help
# Or one-shot:
npx @oratis/lisa "say hi"- Create a separate GitHub repo
https://github.com/oratis/homebrew-tapwith a single fileFormula/lisa.rb(a copy ofpackaging/homebrew/lisa.rbfrom this repo). - For the automated bump (recommended): add a repo secret
HOMEBREW_TAP_TOKENto this repo — a token with write access to the tap repo (the per-repoGITHUB_TOKENcan't push to a different repo):- Fine-grained PAT: Only select repositories →
oratis/homebrew-tap, Repository permissions → Contents: Read and write; or a classic token withreposcope. - Settings → Secrets and variables → Actions → New repository secret →
HOMEBREW_TAP_TOKEN.
- Fine-grained PAT: Only select repositories →
The formula points at the npm tarball (not the GitHub source archive), because
the npm tarball ships pre-built dist/ — that avoids needing TypeScript at brew
install time. So the tap bump must come after npm publish (§1 above): it
pins the sha256 of the freshly-published npm tarball, which must already exist
on the registry (a hash computed any other way risks not matching the registry
bytes and breaking brew install).
Once HOMEBREW_TAP_TOKEN is set, just run the workflow after npm publish:
# After `npm publish` has landed @oratis/lisa@<version> on the registry:
gh workflow run "Release — Homebrew tap" # uses the latest v* tag
# or pin explicitly:
gh workflow run "Release — Homebrew tap" -f version=0.11.0.github/workflows/release-homebrew.yml
fetches the published tarball, computes its sha256, and pushes
Formula/lisa.rb (lisa <version>) to the tap repo. (Also keep the in-repo
template packaging/homebrew/lisa.rb in sync when
convenient — it's the reference copy, not what users install.)
If the token isn't set up, do it by hand:
# 0. Make sure npm publish (§1 above) has run — the npm tarball must exist.
# 1. Compute the sha256 of the npm tarball.
VERSION=$(node -p 'require("./package.json").version')
NPM_TARBALL="https://registry.npmjs.org/@oratis/lisa/-/lisa-${VERSION}.tgz"
SHA=$(curl -sL "$NPM_TARBALL" | shasum -a 256 | cut -d' ' -f1)
echo "version=$VERSION"
echo "sha256=$SHA"
# 2. Edit packaging/homebrew/lisa.rb in this repo:
# url "https://registry.npmjs.org/@oratis/lisa/-/lisa-${VERSION}.tgz"
# sha256 "${SHA}"
# Then copy the same file to the homebrew-tap repo at Formula/lisa.rb.
# 3. Commit + push the tap repo.
cd ../homebrew-tap
git add Formula/lisa.rb
git commit -m "lisa ${VERSION}"
git pushNo-clone alternative (used for v0.14.0 — edits Formula/lisa.rb straight over the
GitHub API, so you don't need a local checkout of homebrew-tap; gh must be authed
with write access to the tap repo). Do this only after npm publish lands the tarball:
VERSION=$(node -p 'require("./package.json").version')
SHA=$(curl -sL "https://registry.npmjs.org/@oratis/lisa/-/lisa-${VERSION}.tgz" | shasum -a 256 | cut -d' ' -f1)
BLOB=$(gh api repos/oratis/homebrew-tap/contents/Formula/lisa.rb --jq .sha)
NEW=$(gh api repos/oratis/homebrew-tap/contents/Formula/lisa.rb --jq .content | base64 -d \
| sed -E "s#lisa-[0-9][0-9.]*\.tgz#lisa-${VERSION}.tgz#g; s#sha256 \"[a-f0-9]{64}\"#sha256 \"${SHA}\"#" | base64)
gh api -X PUT repos/oratis/homebrew-tap/contents/Formula/lisa.rb \
-f message="lisa ${VERSION}" -f content="$NEW" -f sha="$BLOB"
# Verify the pinned hash matches the live tarball before trusting it:
gh api repos/oratis/homebrew-tap/contents/Formula/lisa.rb --jq .content | base64 -d | grep -E 'url "|sha256 "'Users running brew update (next time their auto-update fires) will see the new version.
brew tap oratis/tap
brew install lisa
lisa --help
# Updates:
brew update && brew upgrade lisaThe formula installs Node as a dep and links the lisa bin into Homebrew's prefix. Shell completions also auto-install if the user's shell is set up.
Status: meetlisa.ai purchased. Cloudflare Pages setup pending —
secrets not yet wired, so the deploy step in .github/workflows/website-deploy.yml
is still skipped on push. The workflow builds the Astro site on every
push to main (under website/ paths) regardless, so the build is
known-good before flipping the deploy switch.
-
Domain. ✅ Already purchased:
meetlisa.ai(Cloudflare Registrar / Namecheap / Porkbun all work). -
Create the Cloudflare Pages project.
- Sign in to Cloudflare → Workers & Pages → Create → Pages → Connect to Git.
- Connect this repo (
oratis/LISA). - Project name:
lisa-website(must match the workflow). - Production branch:
main. - Build settings: leave empty — the GH Actions workflow handles building. (Cloudflare's own builder will be skipped because the workflow uses
pages deploydirectly.)
-
Generate API credentials.
- Cloudflare → My Profile → API Tokens → Create Token → "Custom token":
- Permissions:
Account → Cloudflare Pages → Edit - Account Resources:
<your account> - TTL: leave default
- Permissions:
- Copy the token.
- Find your Account ID on the Cloudflare dashboard right sidebar.
- Cloudflare → My Profile → API Tokens → Create Token → "Custom token":
-
Add repo secrets. GitHub → repo Settings → Secrets and variables → Actions → New repository secret:
CF_API_TOKEN= the token from step 3CF_ACCOUNT_ID= the account ID from step 3
-
Push to trigger the deploy.
git commit --allow-empty -m "trigger website deploy" git push origin mainWatch GitHub Actions → "Website — build + deploy" → both jobs should complete green. The deploy job posts the live URL.
-
Custom domain. Cloudflare Pages project → Custom domains → Set up a custom domain → enter
meetlisa.ai. Cloudflare auto-creates the CNAME / TLS cert.
After step 5, every push to main that touches website/, src/web/assets/, scripts/lisa-moods.ts, or the workflow itself triggers a re-deploy.
While the secrets are unset, the deploy job is skipped — the workflow only builds + uploads an artifact (handy for visually verifying changes before going public). To test the site without going public:
cd website
npm install
npm run dev # http://localhost:4321When you publish a new version, do them roughly together:
git tag v0.X.Y && git push --tags- GitHub Release (auto-generated changelog from commits is fine)
npm publish --access public- Update Homebrew formula in tap repo (~5min after npm publish so users can use either)
- Bump website's "current version" badge (if you add one) and re-deploy
Total time per release: ~10 minutes once the credentials are wired.