Turn agent output into pages worth sharing.
One API call turns a CSV into a sortable table, Markdown into styled prose, JSON into an interactive tree.
No accounts, no config, no deploy pipeline — just content in, shareable page out.
curl -X POST https://api.easl.dev/publish \
-H "Content-Type: application/json" \
-d '{"content": "# Hello World\nSome **markdown** here.", "contentType": "text/markdown"}'
# → https://warm-dawn.easl.deveasl auto-detects your content and renders it with the right interactive viewer:
- CSV → sortable table with sticky headers and alternating rows
- Markdown → styled prose with headings, code blocks, and tables
- JSON → collapsible tree with syntax highlighting
- Mermaid → rendered diagram (flowcharts, sequence diagrams, etc.)
- SVG → sanitized, zoomable viewer
- HTML → served as-is
- PDF → embedded viewer
- Images → responsive centered viewer
8 formats. Zero config. All auto-detected.
curl -fsSL https://easl.dev/install.sh | sh
easl publish report.md
# => https://calm-river.easl.dev
easl publish data.csv --title "Q4 Results" --open
cat logs.json | easl publish --type json
easl publish board-update.md --generate-password # password-protected; password printed once
easl publish board-update.md --private # account-private (needs `easl login`)
easl listAdd to your MCP config (Claude Desktop, Cursor, Windsurf, etc.):
{
"mcpServers": {
"easl": {
"command": "npx",
"args": ["-y", "@easl/mcp"]
}
}
}Then just ask your agent:
"Publish this CSV as a shareable table"
"Turn this markdown into a beautiful page"
Give your agent built-in knowledge of easl — content types, viewers, best practices:
npx skills add AdirAmsalem/easlWorks with Claude Code, Codex, Cursor, ChatGPT, Gemini CLI, and more.
curl -X POST https://api.easl.dev/publish \
-H "Content-Type: application/json" \
-d '{"content": "Name,Role\nAlice,Engineer\nBob,Designer", "contentType": "text/csv"}'| Format | Extensions | Rendered as |
|---|---|---|
| CSV | .csv |
Sortable table with sticky headers and alternating rows |
| Markdown | .md |
Styled prose — headings, code blocks, tables, blockquotes |
| JSON | .json |
Collapsible tree with syntax highlighting and expand/collapse all |
| HTML | .html |
Served as-is, no wrapping |
| SVG | .svg |
Sanitized, zoomable viewer (scripts stripped) |
.pdf |
Embedded iframe viewer | |
| Mermaid | .mmd |
Rendered diagram via Mermaid.js (flowcharts, sequence, etc.) |
| Images | .png .jpg .gif .webp |
Responsive centered viewer |
The MCP server gives AI agents first-class publishing capabilities through the Model Context Protocol.
| Tool | Description |
|---|---|
publish_content |
Publish raw content (string) → URL to a shareable page. The fastest path. |
publish_file |
Publish a single file from disk with auto-detected rendering. |
publish_site |
Publish a directory as a multi-page site. |
create_share_link |
Mint a signed, time-limited share URL for an account-private site (requires EASL_API_KEY). |
list_sites |
List sites published in the current session. |
delete_site |
Delete a published site by slug. |
| Variable | Default | Description |
|---|---|---|
EASL_API_URL |
https://api.easl.dev |
API base URL (override for self-hosted) |
EASL_API_KEY |
— | Account API key (easl_…); required to publish account-private sites (private: true) and to use create_share_link |
Pages are public by default. Two independent, composable gates lock one down — set either, both, or neither:
- Password gate —
password(CLI:--password <pw>or--generate-password). Anonymous-publishable. Visitors enter the password once, then stay unlocked for 30 days via a signed cookie. With--generate-password(API:generatePassword: true) easl mints a strong one, returned once in the publish response. - Account gate —
private: true(CLI:--private). Requireseasl login(or an API key) and binds the site to your account; only you — or someone holding a signed share link (easl share <slug>) — can view it.
easl publish board-update.md --generate-password
# => https://cool-maze.easl.dev password: dust-arch-fern-dark-1181
easl login # browser sign-in
easl login --device # headless / remote (no browser callback; approve a code anywhere)
easl publish board-update.md --private # account-private
easl publish board-update.md --private --password "pw" # require BOTH gatesGated pages are never cached, never indexed, and skip OG-image generation. Toggle visibility or rotate the password later with PATCH /sites/:slug/privacy (owner session/Bearer key or claim token).
Base URL: https://api.easl.dev
| Method | Endpoint | Description |
|---|---|---|
POST |
/publish |
Publish content — single-file shorthand or multi-file array (private + password optional) |
GET |
/sites/:slug |
Get site metadata |
PATCH |
/sites/:slug/privacy |
Set the account gate / rotate password (owner session/Bearer key or X-Claim-Token header) |
DELETE |
/sites/:slug |
Delete a site (owner session/Bearer key or X-Claim-Token header) |
POST |
/feedback |
Submit feedback programmatically |
Full API docs: easl.dev/docs
easl runs on Cloudflare's edge network as a single Worker:
- Hono router handles API requests, landing page, docs, and wildcard subdomain serving
- R2 stores uploaded files
- D1 (SQLite) tracks site metadata and version history
- KV caches rendered HTML shells for fast serving
When a site is requested (e.g. warm-dawn.easl.dev), the Worker detects the file type, generates an HTML shell with the right interactive viewer, and embeds the raw data for client-side hydration.
packages/
worker/ → Cloudflare Worker (Hono routes, smart rendering, serving)
cli/ → CLI (npm: @easl/cli)
mcp-server/ → MCP server (npm: @easl/mcp, stdio transport, 5 tools)
Prerequisites: Node.js ≥ 20, a Cloudflare account, and wrangler.
-
Clone and install
git clone https://github.com/AdirAmsalem/easl.git cd easl pnpm install -
Create Cloudflare resources
# Create KV namespace wrangler kv namespace create SITES_KV # Create R2 bucket wrangler r2 bucket create easl-content # Create D1 database wrangler d1 create easl-db
-
Configure — Update
packages/worker/wrangler.tomlwith your resource IDs and domain -
Initialize the database
cd packages/worker pnpm db:migrate -
Deploy
pnpm deploy
pnpm install # Install dependencies
pnpm dev # Start local dev server (wrangler dev)
pnpm test # Run tests
pnpm build # Build all packagesLocal dev uses path-based routing instead of subdomains:
- API endpoints:
http://localhost:8787/publish,/sites - View sites:
http://localhost:8787/s/:slug - Docs:
http://localhost:8787/docs
Contributions are welcome! Whether it's bug fixes, new viewer types, or documentation improvements.
- Fork the repo
- Create your branch (
git checkout -b my-feature) - Make your changes
- Run tests (
pnpm test) - Open a PR
Looking for a place to start? Check out the good first issues.
MIT