{"id":98058,"date":"2026-10-09T19:50:00","date_gmt":"2026-10-09T23:50:00","guid":{"rendered":"https:\/\/overcentral.com\/en\/?p=98058"},"modified":"2026-09-29T08:18:49","modified_gmt":"2026-09-29T12:18:49","slug":"emdash-commands-developers-98058","status":"publish","type":"post","link":"https:\/\/overcentral.com\/en\/emdash-commands-developers-98058\/","title":{"rendered":"8 EmDash Commands Every Developer Should Know"},"content":{"rendered":"<p>Everyone says the same thing about EmDash: learn the admin panel first. Master the dashboard, understand the UI, get comfortable with the block editor. That advice comes from years of WordPress training. It&#8217;s also almost useless for this CMS.<\/p>\n<p>EmDash is not WordPress. The admin panel is deliberately familiar, but the real power lives in places WordPress never had. The CLI. The MCP server. The plugin sandbox manifest. If you only learn the visual interface, you&#8217;re using 20% of what this system does.<\/p>\n<p>Here are eight commands that matter. Some will be obvious. A few will not. That&#8217;s the point.<\/p>\n<h2>1. <code>npm create m-dash@latest<\/code> \u2014 But Not With the Default Template<\/h2>\n<p>The starter command everyone runs. Type it, pick a template, get a site. What the tutorials skip: the template <a href=\"https:\/\/overcentral.com\/en\/ichra-choice-arrangements-label-97925\/\" title=\"ICHRA Gets CHOICE Arrangements Label from CMS, SBA\" data-iacss-internal=\"1\">choice<\/a> locks in your entire schema.<\/p>\n<p>Pick &#8220;blog&#8221; and you get posts, pages, and a comments system. Pick &#8220;portfolio&#8221; and you get projects with client fields and year metadata. Pick &#8220;marketing&#8221; and you get landing page sections. There is no &#8220;generic&#8221; template. Choose carefully from the start, or you&#8217;ll spend the next hour deleting content types you don&#8217;t need.<\/p>\n<p>The command itself is straightforward. The decision it forces is not.<\/p>\n<p>&#8220;`<\/p>\n<p>npm create m-dash@latest<\/p>\n<p>&#8220;`<\/p>\n<h2>2. The MCP Server \u2014 No Command Needed, But You Must Know It Exists<\/h2>\n<p>Every EmDash instance ships with a built-in MCP server. No plugin. No configuration. It just works.<\/p>\n<p>Connect Claude, Cursor, or any MCP-compatible agent to <code>http:\/\/localhost:4321\/mcp<\/code>codecodecode (or your deployed URL). The agent can then query content, create posts, update metadata, and even generate plugins. No custom API wrappers. No authentication headaches beyond the passkey you already set up.<\/p>\n<p>This is the feature WordPress developers miss entirely. They open the admin panel and start clicking. The MCP server means you never have to touch the UI for bulk operations. Ask the agent to &#8220;find all posts mentioning &#8216;legacy&#8217; and add a &#8216;needs-update&#8217; tag.&#8221; Done in one sentence.<\/p>\n<h2>3. <code>m-dash migrate:wordpress<\/code> \u2014 The Import Command That Does More Than You Think<\/h2>\n<p>The WordPress migration tool is not just a content dumper. Point it at your WXR export file, and it maps Yoast SEO fields to EmDash&#8217;s native SEO fields. It reads custom post types. It preserves media associations.<\/p>\n<p>But here&#8217;s what the docs don&#8217;t emphasize: it does <strong>not<\/strong> migrate plugins, themes, or custom functionality. Your WooCommerce store does not come with you. Your Elementor layouts do not survive. The migration imports the data layer only. Everything else is a rebuild.<\/p>\n<p>&#8220;`<\/p>\n<p>m-dash migrate:wordpress &#8211;input=export.xml<\/p>\n<p>&#8220;`<\/p>\n<p>Plan for that rebuild before you run the command, not after.<\/p>\n<h2>4. The Plugin Sandbox Manifest \u2014 <code>capabilities: [...]<\/code><\/h2>\n<p>This is not a command. It&#8217;s a code pattern that defines everything about plugin security. Every EmDash plugin declares its permissions in a manifest. No manifest, no access.<\/p>\n<p>&#8220;`typescript<\/p>\n<p>definePlugin({<\/p>\n<p>  id: &#8220;my-plugin&#8221;,<\/p>\n<p>  version: &#8220;1.0.0&#8221;,<\/p>\n<p>  capabilities: [&#8220;read:content&#8221;, &#8220;email:send&#8221;],<\/p>\n<p>  hooks: {<\/p>\n<p>    &#8220;content:published&#8221;: async (context) =&gt; {<\/p>\n<p>      const email = context.get(&#8220;email&#8221;);<\/p>\n<p>      await email.send({<\/p>\n<p>        to: &#8220;admin@example.com&#8221;,<\/p>\n<p>        subject: &#8220;New post published&#8221;,<\/p>\n<p>      });<\/p>\n<p>    },<\/p>\n<p>  },<\/p>\n<p>});<\/p>\n<p>&#8220;`<\/p>\n<p>The plugin can read content and send email. It cannot write to the database. It cannot access the file system. It cannot make external network calls. The runtime enforces this at the V8 isolate level.<\/p>\n<p>Most developers coming from WordPress write their plugin code first and think about security later. EmDash forces the opposite order. Declare first. Build second.<\/p>\n<h2>5. <code>m-dash content-type:create<\/code> \u2014 Schema as Code, Not Click-Ops<\/h2>\n<p>In the admin panel, you can create a new content type in under a minute. Name it, add fields, set slugs. Done.<\/p>\n<p>The problem: that content type lives only in your database. It is not version-controlled. It is not repeatable. If you tear down your local instance and rebuild, that content type is gone.<\/p>\n<p>The CLI equivalent is better:<\/p>\n<p>&#8220;`<\/p>\n<p>m-dash content-type:create <\/p>\n<p>  &#8211;name=&#8221;Project&#8221; <\/p>\n<p>  &#8211;slug=&#8221;project&#8221; <\/p>\n<p>  &#8211;fields=&#8221;title,description,client,year,url&#8221;<\/p>\n<p>&#8220;`<\/p>\n<p>But even that is a stopgap. What you actually want is to define your schema in code, stored in your repository, deployed alongside your theme. EmDash supports this through its configuration file in <code>astro.config.mjs<\/code>codecodecode. Define content types there, and they become infrastructure-as-code.<\/p>\n<p>The admin panel is convenient. The code-based approach is correct.<\/p>\n<h2>6. <code>m-dash deploy<\/code> \u2014 The Command That Reveals the Lock-In<\/h2>\n<p>Deploy to Cloudflare Workers with one command. It provisions D1 for the database, R2 for media storage, and KV for sessions. It creates the worker routes. It sets up the CDN. The whole process takes about two minutes.<\/p>\n<p>The catch: this deployment path is the only path that gives you sandboxed plugins. Self-host on a Node.js server, and plugins run in-process without isolation. The security model that justifies EmDash&#8217;s existence requires Cloudflare&#8217;s paid runtime.<\/p>\n<p>&#8220;`<\/p>\n<p>m-dash deploy &#8211;provider=cloudflare<\/p>\n<p>&#8220;`<\/p>\n<p>The code is MIT-licensed. The infrastructure is not portable. Know this before you commit to the tool, not after you&#8217;ve built your entire site on it.<\/p>\n<h2>7. <code>m-dash agent:skill --add<\/code> \u2014 The Hidden Developer Multiplier<\/h2>\n<p>EmDash ships with &#8220;agent skills&#8221; files \u2014 structured documentation that tells <a href=\"https:\/\/overcentral.com\/en\/rogue-ai-agents-liability-vacuum-97898\/\" title=\"Rogue AI agents expose liability vacuum as OpenAI faces claims\" data-iacss-internal=\"1\">AI agents<\/a> exactly how to operate the CMS. These are not user-facing docs. They are machine-readable instructions that live in the repository.<\/p>\n<p><a href=\"https:\/\/overcentral.com\/en\/eu-cra-reporting-requirements-80362\/\" title=\"EU CRA Demands What Shipped and When You Knew\" data-iacss-internal=\"1\">When you<\/a> run an MCP agent against your EmDash instance, the agent reads the skills file and immediately knows: how to create content types, how to write plugins, how to manage users, how to deploy changes. No prompting. No trial and error.<\/p>\n<p>The command to add a custom skill:<\/p>\n<p>&#8220;`<\/p>\n<p>m-dash agent:skill &#8211;add=.\/my-custom-skill.md<\/p>\n<p>&#8220;`<\/p>\n<p>Write a skill file that teaches your agent your specific workflow. This is the feature beginners ignore and experienced developers build entire systems around.<\/p>\n<h2>8. The Playground URL \u2014 The Most Underrated &#8220;Command&#8221;<\/h2>\n<p>Not a terminal command. A URL. <code>https:\/\/emdashcms.com\/playground<\/code>codecodecode. It spins up a full EmDash instance in your browser that lasts one hour. No install. No Cloudflare account. No credit card.<\/p>\n<p>This is how you test plugin manifests, experiment with content types, and verify migrations without risking anything. The playground instance is sandboxed, ephemeral, and nobody else can see it.<\/p>\n<p>Bookmark it. Use it before every real deployment.<\/p>\n<h2>What the Common Advice Gets Wrong<\/h2>\n<p>The standard advice \u2014 &#8220;learn the admin panel first&#8221; \u2014 treats EmDash like a reskinned WordPress. It&#8217;s not. The admin panel is deliberately familiar to ease migration, but the system&#8217;s real differentiation lives in the CLI, the MCP server, and the plugin sandbox architecture.<\/p>\n<p>A developer who only knows the visual interface cannot:<\/p>\n<ul>\n<li>Write a sandboxed plugin with a capability manifest<\/li>\n<li>Use AI agents to manage content at scale<\/li>\n<li>Define content types as code in version control<\/li>\n<li>Understand why their deployed instance behaves differently from their local one<\/li>\n<\/ul>\n<p>The eight items above are not a complete list. They are a filter. If you can run all of them comfortably, you understand EmDash. If you cannot, you are still treating it like WordPress with better hosting.<\/p>\n<p>That framing will cost you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Everyone says the same thing about EmDash: learn the admin panel first. Master the dashboard, understand the UI, get comfortable with the block editor. That advice comes from years of WordPress training. It&#8217;s also almost useless for this CMS. EmDash is not WordPress. The admin panel is deliberately familiar, but the real power lives in [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":100123,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98058.png","fifu_image_alt":"8 EmDash Commands Every Developer Should Know","footnotes":""},"categories":[31],"tags":[],"class_list":["post-98058","post","type-post","status-publish","format-standard","has-post-thumbnail","category-technology"],"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98058.png","fifu_image_alt":"8 EmDash Commands Every Developer Should Know","_links":{"self":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98058","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/comments?post=98058"}],"version-history":[{"count":1,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98058\/revisions"}],"predecessor-version":[{"id":100124,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98058\/revisions\/100124"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media\/100123"}],"wp:attachment":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media?parent=98058"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/categories?post=98058"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/tags?post=98058"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}