@floomhq/skills
The Floom Skills CLI: publish, install, sync, and share AI agent skills.
Docs: https://skills.floom.dev/docs
Install
npm i -g @floomhq/skills
Pinned no-install form for automation:
npx -y @floomhq/skills@1.1.0 --help
Login
floom-skills login
The login command starts a browser device flow. Sign in at skills.floom.dev with
Google or email, approve the device code, and the CLI stores the session at
~/.floom/auth.json.
Check the active account:
floom-skills account
First Skill
floom-skills push ~/.claude/skills/my-skill
The folder must contain SKILL.md. Each push creates a Library version.
Create a starter skill when the folder does not exist yet:
floom-skills new my-skill --agent claude
Bulk Sync
floom-skills sync
Zero-arg floom-skills sync detects installed agents and supported scopes, reviews
local-to-Library and Library-to-local differences, and applies the selected
plan. Use --dry-run to preview the plan without changing files or Library
records.
Library-to-local only:
floom-skills pull
floom-skills pull --agent claude,codex
Local-to-Library only:
floom-skills push
Use the installed floom-skills command for interactive terminal work. Use the pinned
npx -y @floomhq/skills@1.1.0 <command> form for automation and agent-run
commands that need reproducible CLI behavior.
Releasing
Releases publish the exact smoke-tested npm tarball via
.github/workflows/publish-cli.yml, triggered by a skills-v* tag.
Provenance is disabled while the source repository remains private.
Hard pre-publish smoke gate
Every npm publish is gated by packages/cli/scripts/pre-publish-smoke.sh,
which packs the tarball, installs it into an isolated $HOME, and drives
every subcommand the way a real user would. If anything fails, the workflow
fails BEFORE npm publish runs — no broken CLI can reach npm latest.
Background: in 2026-05 we shipped 3.0.0 → 3.0.1 → 3.0.2 within hours
because 3.0.0 hit npm latest with three P0s that code review missed:
--help ran the destructive body, --help | head threw an unhandled EPIPE,
and unknown commands silently rendered the dashboard. Only an out-of-band
real-terminal smoke caught them. This script is that smoke, baked into the
publish pipeline.
Before pushing a skills-v* tag
Run the same local gates from the repo root:
pnpm --filter @floomhq/skills --fail-if-no-match lint
pnpm --filter @floomhq/skills --fail-if-no-match test
pnpm --filter @floomhq/skills --fail-if-no-match pack:smoke
packages/cli/scripts/pre-publish-smoke.sh
If anything fails, fix the issue first. Do not push the tag.
Smoke-only workflow run
To validate the smoke script itself without publishing (e.g. after editing
scripts/pre-publish-smoke.sh):
GitHub → Actions → Publish @floomhq/skills → Run workflow
smoke_only: true
The workflow will build, run the smoke, and stop. No npm publish, no
Homebrew dispatch.
Manual publish (rare)
To publish without a tag (e.g. retag an existing version under a different
dist-tag), use workflow_dispatch with smoke_only: false and the desired
tag input. The smoke gate still runs first.
What the pre-publish smoke checks
See scripts/pre-publish-smoke.sh for the full assertion list. Summary:
| 1 | Tarball builds, packs, installs cleanly into isolated $HOME; installed floom-skills --version matches package.json |
| 2 | Every subcommand --help exits 0, starts with Usage: floom-skills, writes no ~/.floom/auth.json, prints no "Signed (in |
| 3 | floom-skills --help | head -3 and floom-skills push --help | head -1 print no EPIPE / "Unhandled error event" (P0 #2 from 3.0.0) |
| 4 | floom-skills <unknown> exits non-zero with "unknown command" + "did you mean" hint (P0 #3 from 3.0.0) |
| 5 | Bare floom-skills --help exits 0 with grouped help |
| 6 | Unauth whoami / account / logout exit 0 idempotent; unauth status / sync --json / push --json exit non-zero with no stack trace |
| 7 | floom-skills logout extra-positional is rejected with non-zero exit AND ~/.floom/auth.json is preserved (no destructive body) |
| 8 | Agent detection picks up fake .claude/, .codex/, .cursor/ marker dirs in the isolated $HOME (verified by parsing floom-skills doctor --json); bare floom-skills sync / floom-skills pull with planted agents do not crash unauth (clean signedIn:false envelope). Note: fan-out behaviour itself requires real auth, so it is exercised at the unit-test layer by src/commands/sync.fanout.test.ts, which the publish workflow runs as a separate hard gate before the smoke. |
If any assertion fails, the publish job fails. The smoke script exits non-zero
on the first failure and prints a summary of every failed check.
Files
packages/cli/
├── src/ # TypeScript source
│ ├── index.ts # CLI entry point (commander)
│ ├── commands/ # one file per subcommand
│ ├── lib/ # shared helpers
│ └── cli-smoke.test.ts # unit-level smoke (P0 lock-ins)
├── scripts/
│ ├── build-bundle.mjs # esbuild → dist/index.js
│ ├── verify-package.mjs # pre-pack file allowlist check
│ └── pre-publish-smoke.sh # E2E smoke driven against tarball
├── package.json
└── CHANGELOG.md