with one click
with one click
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | publish |
| description | Bump version, build, test, publish to npm, and install locally |
| arguments | <patch|minor|major> <-rc> <--check|-ch> |
Automated release pipeline for moflo. Bumps version, commits, builds, tests, runs doctor, publishes to npm, and installs the new version locally.
Arguments: $ARGUMENTS
/publish # patch bump, default mode (skips CI-covered gates)
/publish minor # minor bump (4.8.56 ā 4.9.0)
/publish major # major bump (4.8.56 ā 5.0.0)
/publish -rc # patch RC bump (4.8.56 ā 4.8.57-rc.1)
/publish minor -rc # minor RC bump (4.8.56 ā 4.9.0-rc.1)
/publish --check # full pre-flight (lint + test + smoke + everything)
/publish -ch # short form of --check
/publish minor -ch # combine: full pre-flight on a minor bump
Default (flag absent): runs build + doctor + trigger-based manual checks only. Skips lint/test/smoke because those gates are covered by CI on every PR + push to main (ci.yml, consumer-install-smoke.yml).
With --check or -ch (any presence): runs the full pre-flight from pre-publish-rules.md ā lint, build, test, doctor (strict), clean smoke, populated smoke, and a forced full walk of every manual gate. Use this for publishes that didn't go through a green PR, risky releases, or when you want belt-and-suspenders.
The flag is presence-only. --check and -ch both set it to true. There is no --check=true / --check=false syntax ā absence means false.
patch if not specified-rc flag: produce a release candidate--check or -ch (presence): set CHECK_MODE=true. Otherwise CHECK_MODE=false.-rc: Use npm version <patch|minor|major> --no-git-tag-version-rc: Calculate manually:
4.8.57-rc.3), increment the RC number (ā 4.8.57-rc.4)-rc.1 (e.g., 4.8.56 ā 4.8.57-rc.1)npm version <new-version> --no-git-tag-versionbash .claude/skills/publish/fingerprint.sh
The script diffs HEAD against the most recent chore: install moflo@* commit and pattern-matches the file list against the manual-gate triggers from pre-publish-rules.md. Output is one block:
Triggered manual checks: bin-scriptfiles-sync info-loss-audit
Diff range: <last-publish-sha>..HEAD
Changed files: 7
Triggered manual checks: none means gates 1/2/6 don't apply to this diff ā skip them entirely.
This step costs ~50 tokens and is the cornerstone of token-efficient default mode.
npm run build
Always runs regardless of CHECK_MODE. Syncs the version to src/cli/version.ts via the version lifecycle script, then compiles all TypeScript. Confirms the deliverables on disk are correct.
Must exit 0. If it fails, stop and fix the build error.
CHECK_MODE=true)npm run lint
Skipped by default ā ci.yml runs lint on every PR with max-warnings 0. Run when --check is set.
CHECK_MODE=true)npm test
Skipped by default ā ci.yml runs the full test suite on every PR. Run when --check is set.
Must have 0 test file failures. If any test files fail, retest them individually to distinguish real failures from flaky ones (per broken window theory). Fix all real failures before proceeding.
npx moflo doctor --strict
Doctor is the only check with no CI equivalent ā it inspects local state (daemon lock, embeddings hygiene, sandbox tier, vector-stats freshness) that CI cannot validate for you. Always runs in --strict mode regardless of CHECK_MODE.
Never --fix on the publish path. A release pipeline must fail fast on broken local state, not silently repair it; a doctor that auto-repairs masks the very signal we want ā "something is off, stop and investigate before shipping." If doctor --strict fails, stop and run flo healer --fix (or npx moflo doctor --fix) interactively, verify the repair, then retry the publish.
CHECK_MODE=true)npm run test:smoke
npm run test:smoke:populated
Skipped by default ā consumer-install-smoke.yml runs both profiles on Ubuntu/macOS/Windows on every PR + push to main. Run when --check is set.
Read the fingerprint output from Step 1.
| Trigger | Manual check (gate) | What to walk |
|---|---|---|
split-newlines | Gate 7 | Diff the changed file-reading code; verify any newline split uses /\r?\n/ not '\n' |
homedir-tmpdir | Gate 7 | Verify env-var literals use os.homedir() / os.tmpdir(), not raw process.env.HOME / /tmp |
bwrap-permissions | Gate 7 | Spell bash steps that need network declare permissionLevel: elevated |
posix-only-spell-bash | Gate 7 | Spell bash steps avoid mkdir/rm/cp; use node -e with fs/os for cross-platform file ops |
bin-scriptfiles-sync | Gate 8 | New bin/ script appears in all three scriptFiles arrays (session-start-launcher.mjs, init/moflo-init.ts, third sync site) |
helper-static-files | Gate 8 | New helpers ship as static bin/ files, not generated at runtime |
shipped-guidance-prefix | Gate 8 | New shipped guidance has moflo- prefix and lives in .claude/guidance/shipped/ |
files-glob-coverage | Gate 9 | Run npm pack --dry-run and confirm new shipped files appear in the tarball listing |
info-loss-audit | Gate 10 | For each deleted/renamed file, audit destinations bullet-by-bullet ā every piece of removed content has a home |
If CHECK_MODE=true, walk all manual gates regardless of triggers (full audit). If CHECK_MODE=false, walk only triggered ones.
If the trigger set is none AND CHECK_MODE=false: skip Step 7 entirely.
Commit the version bump files:
git add package.json package-lock.json src/cli/version.ts
git commit -m "chore: bump version to <new-version>"
git push origin main
Only commit version-related files. Do not stage unrelated changes.
npm whoami
If 401 or "not logged in": auth token in ~/.npmrc is missing or expired. Ask the user for a valid npm publish token.
How to create a token (provide these instructions to the user if needed):
moflo packagenpm_...)Once the user provides the token, write it to ~/.npmrc:
echo "//registry.npmjs.org/:_authToken=<token>" > ~/.npmrc
Verify with npm whoami before proceeding.
npm publish --tag <tag>
npm publish (publishes to latest tag by default)npm publish --tag rc (publishes to rc tag so it doesn't become latest)OTP handling:
npm publish --otp=<code> --tag <tag>npm view moflo version
npm view moflo dist-tags
Confirm the published version matches what we just built.
npm install moflo@<new-version> --save-dev
This updates package.json and package-lock.json to use the newly published version as a devDependency.
If package.json or package-lock.json changed from the install:
git add package.json package-lock.json
git commit -m "chore: install moflo@<new-version>"
git push origin main
The chore: install moflo@<version> commit message is the anchor the fingerprint uses to bound future diffs ā keep the prefix exact.
Print a summary at the end:
Publish Summary
āāāāāāāāāāāāāāā
Mode: default | --check
Version: <old> ā <new>
Tag: latest | rc
Build: passed
Tests: skipped (CI-covered) | <N> files passed, <N> tests passed
Lint: skipped (CI-covered) | passed
Doctor: <N> passed, <N> warnings
Smoke (clean): skipped (CI-covered) | passed
Smoke (popl): skipped (CI-covered) | passed
Triggered gates: <list> | none
Published: moflo@<new-version>
Installed: moflo@<new-version> (devDependency)
--force on npm publishprepublishOnly script in package.json runs npm run build automatically, so npm publish will fail-fast on any TypeScript or asset-bundling error even if Step 2 had been skipped (it isn't ā Step 2 always runs).claude/guidance/internal/pre-publish-rules.md ā never duplicate or paraphrase them in this skill; reference and follow--checkUse --check / -ch when:
For the common case ā publishing right after a merged green PR ā the default mode is correct and meaningfully cheaper in tokens and time.
.claude/skills/publish/fingerprint.sh ā Trigger-fingerprint script invoked by Step 1.claude/guidance/internal/pre-publish-rules.md ā Authoritative gate ruleset (gates 1ā10) and trigger mapdocs/BUILD.md ā Step-by-step build/publish process this skill mirrors.claude/guidance/internal/dogfooding.md ā Why we catch consumer-facing regressions first as our own dependencyharness/consumer-smoke/README.md ā Smoke harness profiles (clean + populated) that prove a consumer install works.github/workflows/ci.yml ā Lint/build/test gates this skill skips by default.github/workflows/consumer-install-smoke.yml ā Smoke gates this skill skips by default