| name | emdash-cli |
| description | Use the EmDash CLI to manage content, schema, media, and more. Use this skill when you need to interact with a running EmDash instance from the command line — creating content, managing collections, uploading media, generating types, or scripting CMS operations. |
EmDash CLI
The EmDash CLI (emdash or ec) manages EmDash CMS instances. Commands fall into two categories:
- Local commands — work directly on a SQLite file, no running server needed:
init, dev, seed, export-seed, auth secret
- Remote commands — talk to a running EmDash instance via HTTP:
types, login, logout, whoami, content, schema, media, search, taxonomy, menu
Authentication
Remote commands resolve auth automatically:
--token flag
EMDASH_TOKEN env var
- Stored credentials from
emdash login
- Dev bypass (localhost only — no token needed)
For local dev servers, just run the command — auth is handled automatically. For remote instances, run emdash login --url https://my-site.pages.dev first.
Custom Headers & Reverse Proxies
Sites behind Cloudflare Access or other reverse proxies need auth headers on every request. The CLI supports this via --header flags and environment variables.
Service Tokens (Recommended for CI/Automation)
npx emdash login --url https://my-site.pages.dev \
--header "CF-Access-Client-Id: xxx.access" \
--header "CF-Access-Client-Secret: yyy"
npx emdash login -H "CF-Access-Client-Id: xxx" -H "CF-Access-Client-Secret: yyy"
export EMDASH_HEADERS="CF-Access-Client-Id: xxx
CF-Access-Client-Secret: yyy"
npx emdash login --url https://my-site.pages.dev
Headers are persisted to ~/.config/emdash/auth.json after login, so subsequent commands inherit them automatically.
Cloudflare Access Browser Flow
If you don't have service tokens and cloudflared is installed, the CLI will automatically:
- Detect when Access blocks the request
- Try to get a cached JWT via
cloudflared access token
- Fall back to
cloudflared access login for browser-based auth
This works for interactive use but isn't suitable for CI. Use service tokens for automation.
Generic Reverse Proxy Auth
The --header flag works with any auth scheme:
npx emdash login --url https://example.com -H "Authorization: Basic dXNlcjpwYXNz"
npx emdash login --url https://example.com -H "X-API-Key: secret123"
Quick Reference
Database Setup
Migrations and seed application happen automatically inside the runtime — there's no separate init/seed step. Just start the dev server (or deploy) and the first request runs pending migrations and applies the bundled seed if the database is empty.
npx emdash dev
npx emdash dev --types
mkdir -p .emdash
npx emdash export-seed > .emdash/seed.json
npx emdash export-seed --with-content > .emdash/seed.json
Type Generation
npx emdash types
npx emdash types --url https://my-site.pages.dev
npx emdash types --output src/types/cms.ts
Writes .emdash/types.ts (TypeScript interfaces) and .emdash/schema.json.
Authentication
npx emdash login --url https://my-site.pages.dev
npx emdash whoami
npx emdash logout
npx emdash auth secret
Content CRUD
The CLI is designed for agents. Create and update auto-publish by default so agents get read-after-write consistency without managing drafts.
npx emdash content list posts
npx emdash content list posts --status published --limit 10
npx emdash content get posts 01ABC123
npx emdash content get posts 01ABC123 --raw
npx emdash content get posts 01ABC123 --published
npx emdash content create posts --data '{"title": "Hello", "body": "# World"}'
npx emdash content create posts --file post.json --slug hello-world
npx emdash content create posts --draft --data '...'
cat post.json | npx emdash content create posts --stdin
npx emdash content update posts 01ABC123 --rev MToyMDI2... --data '{"title": "Updated"}'
npx emdash content update posts 01ABC123 --rev MToyMDI2... --draft --data '...'
npx emdash content delete posts 01ABC123
npx emdash content publish posts 01ABC123
npx emdash content unpublish posts 01ABC123
npx emdash content schedule posts 01ABC123 --at 2026-03-01T09:00:00Z
npx emdash content restore posts 01ABC123
Schema Management
npx emdash schema list
npx emdash schema get posts
npx emdash schema create articles --label Articles --description "Blog articles"
npx emdash schema delete articles --force
npx emdash schema add-field posts body --type portableText --label "Body Content"
npx emdash schema add-field posts featured --type boolean --required
npx emdash schema remove-field posts featured
Field types: string, text, number, integer, boolean, datetime, select, multiSelect, image, file, reference, portableText, json, slug, url. See FIELD_TYPE_TO_COLUMN in packages/core/src/schema/types.ts for the authoritative list.
Media
npx emdash media list
npx emdash media list --mime image/png
npx emdash media upload ./photo.jpg --alt "A sunset" --caption "Bristol, 2026"
npx emdash media get 01MEDIA123
npx emdash media delete 01MEDIA123
Search
npx emdash search "hello world"
npx emdash search "hello" --collection posts --limit 5
Taxonomies
npx emdash taxonomy list
npx emdash taxonomy terms categories
npx emdash taxonomy add-term categories --name "Tech" --slug tech
npx emdash taxonomy add-term categories --name "Frontend" --parent 01PARENT123
Menus
npx emdash menu list
npx emdash menu get primary
Drafts and Publishing
The CLI auto-publishes on create and update by default. This means:
create creates the item and immediately publishes it
update updates the item and publishes if a draft revision was created
get returns draft data if a pending draft exists (e.g. from the admin UI)
Use --draft on create/update to skip auto-publishing. Use --published on get to ignore pending drafts.
Collections that support revisions store edits as draft revisions. The CLI handles this transparently — agents don't need to know whether a collection uses revisions or not.
JSON Output
All remote commands support --json for machine-readable output. It's auto-enabled when stdout is piped.
npx emdash content list posts --json | jq '.items[].slug'
ID=$(npx emdash content create posts --data '{"title":"Hello"}' --json | jq -r '.id')
Editing Flow
For details on how content editing works — Portable Text/markdown conversion, _rev tokens, and raw mode — see EDITING-FLOW.md.