| name | release |
| description | Load when cutting a new ei-tui release — version bump, tag, npm publish. Runs the full pre-flight checklist interactively with Flare confirming each gate before proceeding. Triggers: 'cut a release', 'bump the version', 'tag and publish', 'release v0.x.y'. |
Release Skill — ei-tui
You are running a release for the ei-tui package. This is a collaborative, step-by-step process — you run each check, report the result to Flare, and confirm before proceeding. Do not batch steps silently.
Always use the git-master skill for all git operations.
Step 0: Orient
Run these in parallel and report all results to Flare before doing anything else:
node -e "const p = require('./package.json'); console.log(p.version)"
git branch --show-current
git status --short
git tag -l --sort=-version:refname | head -5
Suggest the next patch version (e.g. 0.3.7 → 0.3.8) unless Flare already provided a target.
Confirm the target version with Flare before touching anything.
Pre-Flight Checklist (run in order — stop and report on any failure)
Check 1 — Lockfile sync
npm ci
If this fails: the lockfile is out of sync with package.json. Fix with npm install, commit the updated package-lock.json, then re-run. This broke CI from v0.2.1 through v0.3.1.
Check 2 — Clean working tree
git status --short
If anything shows up: STOP. Ask Flare how to handle the uncommitted changes before proceeding.
Check 2.5 — Did you update the docs?
Mandatory human pause. Ask Flare:
"Did you update the docs? Check README.md, AGENTS.md, src/cli/README.md, tui/README.md for anything stale — new tools, changed behavior, removed fields. If a human would be confused without knowing, update it now."
Do not proceed until Flare explicitly confirms docs are current.
Check 3 — On main, up to date
git branch --show-current
git fetch origin && git status
If not on main or behind origin: STOP. Do not release from a branch or stale checkout.
Check 4 — Unit tests
npm test
If any test fails: STOP.
Check 5 — Structural invariants
bash ci/structural-checks.sh
If any check fails: STOP. These are fast grep-based rules for architectural patterns (prompt builder purity, overlay keyboard registration, etc.). A failure here means a convention was violated that TypeScript won't catch.
Check 6 — Core TypeScript build
npm run build
If this fails: STOP. Fix type errors before releasing. This is what broke v0.1.15.
Check 7 — Web build (BOTH tsc and Vite — they catch different errors)
cd web && npx tsc --noEmit && npx vite build 2>&1 | tail -5
Both must pass independently:
tsc --noEmit catches noUnusedLocals dead-code violations Vite silently ignores
vite build catches bundler/JSX/circular-import errors tsc misses
This is what CI runs. (v0.1.9 = vite caught it; v0.1.18 deploy failure = tsc caught it)
Check 8 — Web E2E tests
CI= npm run test:e2e > .sisyphus/evidence/e2e-pre-release.txt 2>&1; echo "EXIT: $?"
CI= is required. The playwright config uses reuseExistingServer: !process.env.CI — if CI is set (as it is in the agent's default env), Playwright refuses to reuse Flare's running dev server and fails with a port conflict instead of running the tests.
Save to file, then grep the summary:
grep -E "(passed|failed)" .sisyphus/evidence/e2e-pre-release.txt | tail -5
If any test fails: STOP.
Check 9 — TUI E2E tests
CI cannot run these — tui-e2e-experimental.yml is manual-trigger only because tui-test requires Node 20 and native PTY bindings that break on newer versions. The skill runs them locally where Node 20 is available via nvm.
cd tui && npm run test:e2e > ../.sisyphus/evidence/tui-e2e-pre-release.txt 2>&1; echo "EXIT: $?"
The npm run test:e2e script in tui/package.json handles the nvm use 20 switch automatically. Save to file, then check:
grep -E "(passed|failed|FAILED)" ../.sisyphus/evidence/tui-e2e-pre-release.txt | tail -5
If any test fails: STOP.
Check 10 — Prompt eval coverage
Only runs if prompt files changed since the last tag. First, check:
git diff $(git describe --tags --abbrev=0)..HEAD --name-only -- src/prompts/
If nothing changed in src/prompts/: skip this check entirely.
If prompts did change:
10a — Identify changed prompts and their evals
Show Flare:
- Which prompt files changed (from the diff above)
- Which eval files exist for those prompts — convention is
tests/evals/<prompt-name>.eval.ts matching the prompt filename (e.g. topic-scan.ts → topic-scan.eval.ts)
- The actual diff of each changed prompt section so Flare can see what moved
git diff $(git describe --tags --abbrev=0)..HEAD -- src/prompts/
10b — Human adequacy review (mandatory pause)
Present the mapping and ask Flare:
"These prompts changed: [list]. These evals cover them: [list]. Any gaps or evals that don't cover the actual change? Say yes to continue, no to stop and write more evals first."
Do not proceed past this point without an explicit yes from Flare. This is intentionally a human judgment call — eval adequacy is too contextual to automate reliably right now.
10c — Run the relevant evals
Run only the evals that map to changed prompts. Use the file-match argument to target specific suites:
npm run test:evals -- <file-match> > .sisyphus/evidence/evals-pre-release.txt 2>&1; echo "EXIT: $?"
For example, if person-scan.ts and topic-scan.ts changed:
npm run test:evals -- person-scan >> .sisyphus/evidence/evals-pre-release.txt 2>&1
npm run test:evals -- topic-scan >> .sisyphus/evidence/evals-pre-release.txt 2>&1
Check results:
grep -E "(passed|failed|FAILED|✓|✗)" .sisyphus/evidence/evals-pre-release.txt | tail -20
These run against local Gemma (with thinking enabled by default) and take roughly as long as both E2E suites combined — budget 10-15 minutes.
Interpreting failures — three categories:
❌ Unexpected failure (no special tag, not borderline): STOP. Something regressed.
⚠️ borderline failure (tagged borderline, has pass_threshold): Check the pass rate against the threshold. If it met the threshold → continue. If it fell below → treat as unexpected failure and STOP.
💬 known-model-limitation failure: Do NOT block. But cross-reference against the changed prompts from 10a:
grep -B2 "known-model-limitation\|✗" .sisyphus/evidence/evals-pre-release.txt | grep "✗"
-
If the failing known-model-limitation case maps to a prompt that did NOT change this release → note it, continue.
-
If the failing known-model-limitation case maps to a prompt that DID change this release → pause and surface to Flare:
"The [case name] case is a known model limitation but its prompt changed this release. It still fails. Is that expected given the change, or does it warrant investigation before we ship?"
This is not a blocker — Flare decides. But it's worth the conversation.
After all 10 checks pass (with known-limitation failures noted and discussed as needed), report a clean summary to Flare and ask for explicit go-ahead before cutting the release.
Release Steps (only after Flare confirms)
-
Bump version in package.json — update the "version" field.
-
Commit:
git add package.json
git commit -m "chore: bump to v{VERSION}"
-
Tag:
git tag v{VERSION}
-
Push commit then tags:
git push && git push --tags
GitHub Actions picks up the tag and publishes to npm via OIDC (no stored secrets). The tag also re-runs the full CI suite — if tests fail there, the publish job will not run.
Release Notes (write while CI runs — don't wait for green)
1. Collect the commits
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --oneline
Skip: merge commits, chore: bump to v* commits.
2. Check if this is the first GitHub Release
gh release list --limit 1
3. Draft the body
If no prior GitHub Releases exist, open with:
👋 Ohai, didn't see you there! Ei has been shipping quietly since v0.1.0 — check the README for background on what it is and how to get started. These notes cover what's new in this release specifically.
For all releases, group into sections — write for a human reader, not a git log. Use the flare-voice skill for tone: direct, punchy, occasionally self-deprecating. Skip anything that's purely internal scaffolding.
## What's New
<!-- feat commits — describe the user-facing change, not the implementation -->
## Fixed
<!-- fix commits — say what was wrong and what it felt like, briefly -->
## Under the Hood
<!-- refactor/test/chore — one short line each, or just skip entirely if boring -->
4. Create the release
Write the body to a temp file, then:
gh release create v{VERSION} \
--title "v{VERSION}" \
--notes-file /tmp/ei-release-notes.md
5. Confirm CI goes green
gh run list --limit 3
The publish job gates on CI — if tests fail, npm doesn't get updated even though the tag exists.
Hard Rules
- Never skip a preflight check, even if "we just ran tests" — this includes Check 9 (TUI E2E) and Check 10 (prompt evals), neither of which CI runs
- Never tag from a branch — must be on
main
- Never tag with uncommitted changes unrelated to the version bump
- Always confirm the target version with Flare before bumping
package.json
- Always confirm all checks passed before tagging
- Use
git-master skill for every git operation