laughing-man is a CLI tool that turns a folder of Markdown files into a newsletter: a static archive site on Cloudflare Pages and email delivery via Resend Broadcasts. Built with Bun + TypeScript.
laughing-man init # Generate laughing-man.yaml
laughing-man setup web # Create Cloudflare Pages project + custom domain + DNS
laughing-man setup newsletter # Verify Resend API key + sender domain + DNS records
laughing-man build # Validate + generate site + email HTML (excludes drafts)
laughing-man preview # Build (including drafts) + local server with live reload
laughing-man stamp # Add frontmatter to .md files that don't have it
laughing-man deploy # Deploy to Cloudflare Pages via wrangler
laughing-man send <N> # Send issue N via Resend Broadcast
laughing-man send status # Show delivery status for all sent broadcasts
Install from npm: npm install -g laughing-man-cli
Or run without installing: npx laughing-man-cli <command>
- Runtime: Node.js 22+ (published package). Bun for development/testing.
- Language: TypeScript (strict mode)
- Templates: Plain TypeScript functions returning HTML strings (no React, no JSX)
- Email: MJML for responsive email HTML
bun test # Run tests
bun run typecheck # TypeScript check
bun run build # Compile TS + copy assets to dist/
bun src/cli.ts --help # Run CLI locallyA PostToolUse hook auto-runs bun run build when source files are edited. If the hook is not active, run it manually after code changes to keep dist/ in sync.
Run bun link from the project root to register the package globally. This symlinks to source, so code changes take effect immediately without re-running.
bun link # One-time setup
laughing-man --help # Works from any directoryRe-run bun link after Bun upgrades or if laughing-man stops resolving.
- Bump the version in
package.json - Update
CHANGELOG.mdwith the new version's changes - Commit the version bump and push to
main - Tag the commit and push the tag:
git tag v<version> git push origin v<version>
- The
publish.ymlworkflow runs onv*tags: typechecks, tests, verifies the tag matchespackage.jsonversion, then publishes to npm with provenance via Trusted Publishing (OIDC).
When you need information about tools used in this project, use the find-docs skill or the Cloudflare skills listed below.
Use these skills for Cloudflare-specific work. They pull from Cloudflare docs and cover best practices.
| Skill | Use when |
|---|---|
cloudflare |
General Cloudflare platform work (Workers, Pages, KV, D1, R2, AI) |
wrangler |
Running wrangler commands, configuring wrangler.jsonc |
workers-best-practices |
Writing or reviewing Workers/Pages Functions code |
Pre-resolved IDs for the find-docs skill. Pass directly to ctx7 docs, skipping the ctx7 library step:
| Tool | libraryId |
|---|---|
| Bun | /oven-sh/bun |
| TypeScript | /microsoft/typescript |
| Zod v4 | /websites/zod_dev_v4 |
| gray-matter | /jonschlinkert/gray-matter |
| marked | /markedjs/marked |
| shiki | /shikijs/shiki |
| Resend SDK | /resend/resend-node |
| Resend API | /websites/resend |
| Wrangler | /cloudflare/workers-sdk |
| Cloudflare SDK | /cloudflare/cloudflare-typescript |
| Cloudflare Pages | /websites/developers_cloudflare_pages |
| Cloudflare Workers (Pages Functions runtime) | /websites/developers_cloudflare_workers |
| MJML | /mjmlio/mjml |
| js-beautify | /beautifier/js-beautify |
| yaml | /eemeli/yaml |
| Open Graph Protocol | /facebook/open-graph-protocol |