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.
Prerequisites
- Node.js 24.0.0+ (recommended: 24.14.0), pnpm 10.28.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 docs for list)
- GitHub CLI (
Setup
# Fork this repo, then clone your fork
git clone https://github.com/<you>/yoda.git
cd yoda
# 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
# Format, lint, type check, and test
pnpm run format
pnpm run lint
pnpm run typecheck
pnpm run testTip: During development, the renderer hot‑reloads. Changes to the Electron main process (files in src/main) require a restart of the dev app.
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)
- Create a feature branch
git checkout -b feat/<short-slug>
- 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.
- Run checks locally
pnpm run format # Format code with Prettier (required)
pnpm run lint # ESLint
pnpm run typecheck # TypeScript type checking
pnpm run test # Vitest test suite
Pre-commit hooks run automatically via Husky + lint-staged. On each commit, staged files are auto-formatted with Prettier and linted with ESLint. Run the full local gate before opening or merging a PR.
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.
- 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 integration
- Open a Pull Request
- Describe the change, rationale, and testing steps.
- Link related Issues.
- Keep the PR title in Conventional Commit format if possible.
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 lint-- ESLint across all filespnpm run typecheck-- TypeScript type checking (whole project)pnpm run test-- 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
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/yoda/yoda.db - Linux:
~/.config/yoda/yoda.db - Windows:
%APPDATA%\yoda\yoda.db
- macOS:
- Reset: quit the app, delete the file, relaunch (the schema is recreated).
- Use GitHub Issues. Include:
- OS, Node version
- Steps to reproduce
- Relevant logs (renderer console, terminal output)
- Screenshots/GIFs for UI issues
Prepare the release metadata without creating a tag yet:
# Keep these two versions in sync, then add a matching CHANGELOG section.
node -p "require('./package.json').version"
head -n 12 CHANGELOG.mdRun the complete repository gates before committing:
pnpm run format
pnpm run lint
pnpm run typecheck
pnpm test
pnpm run build
pnpm run docs:buildCommit and push the release metadata first. Then create and push exactly one matching tag (for example, v0.18.10). The tag push dispatches the production release automatically; do not also dispatch the workflow manually for the same tag.
The release pipeline is split across these GitHub Actions workflows:
Production Release (.github/workflows/release-prod.yml):
- Builds Linux, Windows, and macOS packages
- Signs Windows builds when Azure Trusted Signing secrets are configured
- Signs, verifies, notarizes, and staples macOS DMGs
- Publishes the GitHub Release only after all platform jobs succeed
- Dispatches the China mirror as an independent post-release workflow
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 and uploads the Nix artifact when available
Canary Release (.github/workflows/release-canary.yml):
- Builds Linux, Windows, and macOS packages with the canary config
- Publishes artifacts to the
v1-canaryR2 channel