---
title: Contributing to EmDash
description: How to set up a development environment and contribute to EmDash.
---

import { Aside, Steps, Tabs, TabItem } from "@astrojs/starlight/components";

EmDash is a pnpm monorepo. The main package is `packages/core` (published as `emdash`) — it contains the Astro integration, REST API, database layer, schema management, and plugin system. The admin UI lives in `packages/admin`.

For the full contributor reference — repo layout, architecture, code conventions, changeset policy — see [CONTRIBUTING.md](https://github.com/emdash-cms/emdash/blob/main/CONTRIBUTING.md).

## Local Setup

<Steps>

1. **Clone and install**

   ```bash
   git clone https://github.com/emdash-cms/emdash.git
   cd emdash
   pnpm install
   pnpm build    # required before first run
   ```

2. **Start the demo**

   ```bash
   cd demos/simple
   pnpm dev
   ```

   The setup wizard runs automatically on first launch — it creates the database, runs migrations, and prompts you to create an admin account.

   To populate with sample content: `pnpm seed`

3. **Open the admin**

   Visit [http://localhost:4321/_emdash/admin](http://localhost:4321/_emdash/admin)

   In dev mode, you can skip passkey auth with the bypass endpoint:

   ```
   http://localhost:4321/_emdash/api/setup/dev-bypass?redirect=/_emdash/admin
   ```

</Steps>

## Development Workflow

### Watch Mode

For iterating on core packages alongside the demo, run two terminals:

```bash
# Terminal 1 — rebuild packages/core on change
cd packages/core && pnpm dev

# Terminal 2 — run the demo
cd demos/simple && pnpm dev
```

### Checks

Run these before committing (from the repo root):

```bash
pnpm typecheck    # TypeScript
pnpm lint         # full type-aware lint
pnpm format       # auto-format (oxfmt, tabs)
```

<Aside type="caution">
  Type checking and linting must both pass. Don't commit with known failures.
</Aside>

### Tests

<Tabs>
<TabItem label="All tests">
```bash
pnpm test
```
</TabItem>
<TabItem label="Core only">
```bash
cd packages/core && pnpm test
```
</TabItem>
<TabItem label="Watch mode">
```bash
cd packages/core && pnpm test --watch
```
</TabItem>
<TabItem label="E2E">
```bash
pnpm test:e2e    # starts its own server
```
</TabItem>
</Tabs>

Tests use real in-memory SQLite — no mocking. Each test gets a fresh database.

## What We Accept

| Type             | Process                                                                                       |
| ---------------- | --------------------------------------------------------------------------------------------- |
| **Bug fixes**    | Open a PR directly. Include a failing test.                                                   |
| **Docs / typos** | Open a PR directly.                                                                           |
| **Translations** | Open a PR directly. See [Translating EmDash](/contributing/translating/).                      |
| **Features**     | Open a [Discussion](https://github.com/emdash-cms/emdash/discussions/categories/ideas) and wait for a maintainer to approve it. |
| **Refactors**    | Open a Discussion first.                                                                      |

Feature PRs without prior maintainer approval will be closed.

For the full contribution policy, changeset guide, repo layout, and architecture overview, see [CONTRIBUTING.md](https://github.com/emdash-cms/emdash/blob/main/CONTRIBUTING.md).
