Skip to main content
Each project can have a .emdash.json file at its root to customize Emdash’s behavior for that specific project. This file is optional and should be committed to version control so all team members share the same configuration.

Configuration file location

Place .emdash.json in your project’s root directory (the same directory as your .git folder):
my-project/
├── .git/
├── .emdash.json    # Project configuration
├── package.json
└── src/

Configuration schema

Here’s the complete schema for .emdash.json:
{
  "preservePatterns": ["pattern1", "pattern2"],
  "shellSetup": "command to run on shell startup",
  "scripts": {
    "setup": "optional setup command",
    "run": "optional run command",
    "teardown": "optional teardown command"
  }
}

Preserve patterns

By default, Emdash copies certain gitignored files (like .env files) from your main repository to task worktrees. You can customize which files are preserved using preservePatterns.
preservePatterns
array
Array of glob patterns for files to copy from the main repo to task worktrees. These patterns are matched against gitignored files.Default patterns (if not specified):
[
  ".env",
  ".env.keys",
  ".env.local",
  ".env.*.local",
  ".envrc",
  "docker-compose.override.yml"
]

Use cases for preserve patterns

If you use Claude-specific commands or configuration:
{
  "preservePatterns": [
    ".env",
    ".env.local",
    ".claude/**"
  ]
}
For local development with SQLite or other file-based databases:
{
  "preservePatterns": [
    ".env",
    "*.db",
    "*.sqlite3"
  ]
}
Share IDE configuration across worktrees:
{
  "preservePatterns": [
    ".env",
    ".vscode/settings.json",
    ".idea/**"
  ]
}
For projects requiring local certificates:
{
  "preservePatterns": [
    ".env",
    "certs/**",
    "*.pem",
    "*.key"
  ]
}
Files in the following directories are never preserved, even if they match patterns:
  • node_modules
  • .git
  • vendor
  • .cache
  • dist
  • build
  • .next
  • .nuxt
  • __pycache__
  • .venv
  • venv

Shell setup

Run custom commands when shells are initialized in task worktrees.
shellSetup
string
Shell command(s) to execute when starting a terminal in a task worktree. Useful for activating virtual environments, loading environment variables, or setting up project-specific tools.
{
  "shellSetup": "source venv/bin/activate"
}

Shell setup examples

{
  "shellSetup": "source .venv/bin/activate"
}
{
  "shellSetup": "export $(cat .env | xargs)"
}
Or if using direnv:
{
  "shellSetup": "eval \"$(direnv hook bash)\""
}
{
  "shellSetup": "nvm use"
}
Chain multiple setup commands:
{
  "shellSetup": "nvm use && pnpm install && source .env"
}
shellSetup commands run every time a shell is started in a worktree. Keep commands fast to avoid slowing down terminal startup.

Lifecycle scripts

Define custom scripts that run at different points in a task’s lifecycle.
scripts.setup
string
Command to run when a task worktree is first created. Use for one-time setup like installing dependencies.
{
  "scripts": {
    "setup": "pnpm install"
  }
}
scripts.run
string
Command to run when starting work on a task. Use for development servers or watch processes.
{
  "scripts": {
    "run": "npm run dev"
  }
}
scripts.teardown
string
Command to run when cleaning up a task worktree. Use for stopping services or cleaning temporary files.
{
  "scripts": {
    "teardown": "docker-compose down"
  }
}

Lifecycle script examples

{
  "scripts": {
    "setup": "pnpm install && pnpm run build",
    "run": "pnpm run dev",
    "teardown": "pnpm run cleanup"
  }
}
{
  "scripts": {
    "setup": "docker-compose build",
    "run": "docker-compose up -d",
    "teardown": "docker-compose down -v"
  }
}
{
  "scripts": {
    "setup": "python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt",
    "run": "source .venv/bin/activate && python app.py",
    "teardown": "deactivate"
  }
}

Complete examples

Next.js project

.emdash.json
{
  "preservePatterns": [
    ".env",
    ".env.local",
    ".env.development.local"
  ],
  "shellSetup": "nvm use",
  "scripts": {
    "setup": "pnpm install",
    "run": "pnpm run dev"
  }
}

Python Django project

.emdash.json
{
  "preservePatterns": [
    ".env",
    "*.db",
    "media/**"
  ],
  "shellSetup": "source .venv/bin/activate",
  "scripts": {
    "setup": "python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt && python manage.py migrate",
    "run": "source .venv/bin/activate && python manage.py runserver",
    "teardown": "deactivate"
  }
}

Docker Compose project

.emdash.json
{
  "preservePatterns": [
    ".env",
    ".env.local",
    "docker-compose.override.yml",
    "certs/**"
  ],
  "scripts": {
    "setup": "docker-compose build",
    "run": "docker-compose up -d",
    "teardown": "docker-compose down"
  }
}

Monorepo with pnpm

.emdash.json
{
  "preservePatterns": [
    ".env",
    ".npmrc",
    "apps/*/.env.local",
    "packages/*/.env.local"
  ],
  "shellSetup": "nvm use",
  "scripts": {
    "setup": "pnpm install --frozen-lockfile",
    "run": "pnpm run dev"
  }
}

Branch prefix configuration

To customize the Git branch prefix for tasks, use the application settings (not .emdash.json):
settings.json
{
  "repository": {
    "branchPrefix": "your-prefix"
  }
}
This creates branches like your-prefix/task-name-abc instead of the default emdash/task-name-abc. See Application settings for more details.

Build docs developers (and LLMs) love