Contributing
Help improve Emdash - contribution guidelines and development setup
Thanks for your interest in contributing! We favor small, focused PRs and clear intent over big bangs. This guide explains how to get set up, the workflow we use, and a few project‑specific conventions.
Quick Start
Prerequisites
- Node.js 20.0.0+ (recommended: 22.20.0) and Git
- Optional (recommended for end‑to‑end testing):
- GitHub CLI (
brew install gh; thengh auth login) - At least one supported coding agent CLI (see Providers)
- GitHub CLI (
Setup
# Fork this repo, then clone your fork
git clone https://github.com/<you>/emdash.git
cd emdash
# Use the correct Node.js version (if using nvm)
nvm use
# Quick start: install dependencies and run dev server
pnpm run d
# Or run separately:
pnpm install
pnpm run dev
# Type checking, lint, build
pnpm run type-check
pnpm run lint
pnpm run buildTip: During development, the renderer hot‑reloads. Changes to the Electron main process (files in src/main) require a restart of the dev app.
Project Overview
src/main/– Electron main process, IPC handlers, services (Git, worktrees, PTY manager, DB, etc.)src/renderer/– React UI (Vite), hooks, components- Local database – SQLite file created under the OS userData folder (see "Local DB" below)
- Worktrees – Git worktrees are created outside your repo root in a sibling
worktrees/folder - Logs – Agent terminal output and app logs are written to the OS userData folder (not inside repos)
Development Workflow
1. Create a feature branch
git checkout -b feat/<short-slug>2. Make changes and keep PRs small and focused
- Prefer a series of small PRs over one large one.
- Include UI screenshots/GIFs when modifying the interface.
- Update docs (README or inline help) when behavior changes.
3. Run checks locally
pnpm run format # Format code with Prettier (required)
pnpm run type-check # TypeScript type checking
pnpm run lint # ESLint
pnpm run build # Build both main and rendererPre-commit hooks run automatically via Husky + lint-staged. On each commit, staged files are auto-formatted with Prettier and linted with ESLint. You don't need to remember to run these manually. Type checking and tests run in CI only since they need the full project context and are slower to execute.
If you need to skip the hook for a work-in-progress commit, use git commit --no-verify. The checks will still run in CI when you open a PR.
4. Commit using Conventional Commits
feat:– new user‑facing capabilityfix:– bug fixchore:,refactor:,docs:,perf:,test:etc.
Examples:
fix(opencode): change initialPromptFlag from -p to --prompt for TUI
feat(docs): add changelog tab with GitHub releases integration5. Open a Pull Request
- Describe the change, rationale, and testing steps.
- Link related Issues.
- Keep the PR title in Conventional Commit format if possible.
Code Style and Patterns
TypeScript + ESLint + Prettier
Pre-commit hooks handle formatting and linting automatically on staged files. For full-project checks you can run them manually:
pnpm run format-- format all files with Prettierpnpm run type-check-- TypeScript type checking (whole project)pnpm run lint-- ESLint across all filespnpm exec vitest run-- run the test suite
Electron main (Node side)
- Prefer
execFileoverexecto avoid shell quoting issues. - Never write logs into Git worktrees. All logs belong in the Electron
userDatafolder. - Be conservative with console logging; noisy logs reduce signal. Use clear prefixes.
Git and worktrees
- The app creates worktrees in a sibling
../worktrees/folder. - Do not delete worktree folders from Finder/Explorer; if you need cleanup, use:
git worktree prune(from the main repo)- or the in‑app workspace removal
Documentation
When writing or updating docs, keep the tone clear and conversational. Use complete sentences and natural language rather than long bullet point lists. Avoid em dashes (—); use commas, periods, or rephrase instead.
Renderer (React)
- Components live under
src/renderer/components; hooks undersrc/renderer/hooks. - Agent CLIs are embedded via terminal emulation (xterm.js) - each agent runs in its own PTY.
- Use existing UI primitives and Tailwind utility classes for consistency.
- Aim for accessible elements (labels,
aria-*where appropriate).
Local DB (SQLite)
Location (Electron app.getPath('userData')):
- macOS:
~/Library/Application Support/emdash/emdash.db - Linux:
~/.config/emdash/emdash.db - Windows:
%APPDATA%\emdash\emdash.db
Reset: quit the app, delete the file, relaunch (the schema is recreated).
Issue Reports and Feature Requests
Use GitHub Issues. Include:
- OS, Node version
- Steps to reproduce
- Relevant logs (renderer console, terminal output)
- Screenshots/GIFs for UI issues
Release Process (maintainers)
Use pnpm's built-in versioning to ensure consistency:
# For bug fixes (0.2.9 → 0.2.10)
pnpm version patch
# For new features (0.2.9 → 0.3.0)
pnpm version minor
# For breaking changes (0.2.9 → 1.0.0)
pnpm version majorThis automatically:
- Updates
package.jsonandpnpm-lock.yaml - Creates a git commit with the version number (e.g.,
"0.2.10") - Creates a git tag (e.g.,
v0.2.10)
Then push to trigger the CI/CD pipeline.
What happens next
Two GitHub Actions workflows trigger on version tags:
macOS Release (.github/workflows/release.yml):
- Builds the TypeScript and Vite bundles
- Signs the app with Apple Developer ID
- Notarizes via Apple's notary service
- Creates a GitHub Release with DMG artifacts for arm64 and x64
Linux/Nix Build (.github/workflows/nix-build.yml):
- Computes the correct dependency hash from
pnpm-lock.yaml - Builds the x86_64-linux package via Nix flake
- Pushes build artifacts to Cachix