CodeNomad/CONTRIBUTING.md
Pascal André 4359b4bfe9
fix(v2): align with current OpenCode client contract
Pin the server and UI client to the installed beta runtime and reject mismatched CLI versions before shared-service startup. Delegate proven shared-service shutdown to Service.stop while retaining CodeNomad lease, peer, registration, endpoint, and process-identity checks.

Adopt native Forms and the client/solid data reducer for live messages, tools, permissions, and input forms. Propagate internal stream generations into authoritative reconnect reconciliation and replace directory-wide session scans with native project cursor pagination.

Fail worktree deletion when session evacuation fails and deduplicate canonical workspace folders instead of exposing non-isolated duplicate instances. Update migration notes and CI coverage for the reviewed contract.

Validated with server/UI/Electron typechecks, 244 UI partition tests, 122 Electron native tests, 248 server tests plus 3 platform skips (the sole Windows cleanup race passed in isolation), UI/server/Electron builds, Tauri cargo check --locked, and git diff --check.
2026-08-19 01:50:39 +02:00

7 KiB

Contributing to CodeNomad

Thank you for your interest in contributing! This guide will help you get started.

Prerequisites

  • Node.js 18+ and npm
  • OpenCode CLI in your PATH (CodeNomad uses one shared native V2 service for all workspace locations)

Quick Start

git clone https://github.com/NeuralNomadsAI/CodeNomad.git
cd CodeNomad
npm install
npm run dev

Finding Issues to Work On

Browse open issues and look for these labels:

Label Meaning
ready-to-work Clear scope, ready for anyone to pick up
good-first-issue Good for first-time contributors
enhancement New feature requests
bug Bug reports

Before starting: comment on the issue so we can discuss approach and avoid duplicate work.

Development Workflow

1. Fork and Branch

# Fork the repo on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/CodeNomad.git
cd CodeNomad

# Add the upstream remote
git remote add upstream https://github.com/NeuralNomadsAI/CodeNomad.git

# Create a branch from upstream/dev
git fetch upstream
git checkout -b fix/your-branch-name upstream/dev

2. Branch Naming

Prefix Use for
fix/ Bug fixes
feat/ New features
docs/ Documentation changes
refactor/ Code refactoring
chore/ Build, config, maintenance

Examples: fix/question-queue-ordering, feat/retry-tool-call, docs/contributing-guide

3. Make Your Changes

# Install dependencies
npm install

# Run the dev server
npm run dev

# Run type checking
npm run typecheck --workspace @codenomad/ui

4. Commit

Write clear, descriptive commit messages. Explain what changed and why.

git add .
git commit -m "fix(ui): preserve question queue order when upserting duplicate requests

When a question arrives as a global entry and later resolves to a tool
part with a newer timestamp, the original enqueue time was lost, causing
the question to move behind newer entries and break interruption order."

5. Push and Create a PR

git push origin your-branch-name

Then open a pull request on GitHub targeting the dev branch.

PR checklist:

  • Branch is based on latest upstream/dev
  • One issue per PR (don't mix unrelated changes)
  • Type checking passes: npm run typecheck (root) or the workspace-specific script matching your change area
  • Tests pass (if applicable)
  • PR description explains the change, includes relevant screenshots for UI changes, and links related issues when applicable

Project Structure

Package Description
packages/server Core logic & CLI — workspaces, OpenCode proxy, API, auth
packages/ui SolidJS frontend — reactive UI components and stores
packages/electron-app Electron desktop shell
packages/tauri-app Tauri desktop shell (experimental)
packages/cloudflare Cloudflare deployment adapters

OpenCode V2 Boundaries

  • Server, UI, and the selected opencode2 CLI must use the exact @opencode-ai/client version pinned by the server package. Startup probes and rejects mismatched CLIs. Review OpenCode release notes, current documentation, and installed declarations on every upgrade; this is not the public @opencode-ai/sdk contract.
  • Upgrade references: OpenCode releases, OpenCode documentation, and node_modules/@opencode-ai/client/dist/promise/.
  • packages/server/src/workspaces/opencode-service.ts owns a custom lease-locked discovery, launch, process-proof, and authenticated-stop lifecycle. Production does not call Service.ensure or Service.stop directly. Workspaces are native OpenCode locations/directories, not separate server processes.
  • V2 always uses ~/.local/share/opencode2/opencode.db. Never reuse the V1 database for V2.
  • OpenCode session calls use /workspaces/:id/instance/api/*; CodeNomad control routes and multiplexed events use /api/* and /api/events.
  • The proxy is method/path allowlisted, so new upstream functionality is not exposed automatically.
  • Native Shell (client.session.shell) and prompt instructions (client.session.instructions.entry) remain separate from native V2 PTY management.
  • Native PTYs are location-scoped and listed in the Status panel. The UI refreshes them on PTY events and reconnect, displays native metadata, and supports title updates and ownership-checked removal. Current installed declarations have no PTY output/read/stream API or separate stop endpoint, so removal is the native stop action for a running PTY. packages/opencode-plugin and the server plugin/background-process paths remain deleted and must not be restored.
  • Native events are volatile. Reconnect handlers must refetch authoritative state instead of assuming missed events will replay.
  • Git mutations and Yolo policy remain CodeNomad-owned server boundaries.

Key UI Files

Path Purpose
packages/ui/src/stores/session-events.ts SSE event handlers (idle, status, permissions, questions)
packages/ui/src/stores/session-actions.ts User actions (send message, abort, revert, fork)
packages/ui/src/stores/message-v2/ Message store (v2 architecture)
packages/ui/src/stores/instances.ts Instance management and interruption queues
packages/ui/src/components/tool-call.tsx Tool call rendering
packages/ui/src/components/message-block.tsx Message display blocks
packages/ui/src/components/session/session-view.tsx Main session view
packages/ui/src/lib/i18n/messages/ Translation files (en, es, fr, ja, ru, he, zh-Hans)

For the package map, native OpenCode V2 integration, ownership boundaries, and feature traces, load the codenomad-architecture-guide skill: .opencode/skills/codenomad-architecture-guide/SKILL.md

Styling

  • Tokens: packages/ui/src/styles/tokens.css
  • Utilities: packages/ui/src/styles/utilities.css
  • Component styles: packages/ui/src/styles/components/, packages/ui/src/styles/messaging/, packages/ui/src/styles/panels/
  • Keep style files under ~150 lines; split by component

Internationalization (i18n)

  • Use useI18n() in components, tGlobal() in stores
  • Messages live in packages/ui/src/lib/i18n/messages/<locale>/
  • When adding a string: add to en/ first, then add the same key to every other locale
  • Placeholders use {name} syntax (word characters only)

Code Principles

  • KISS: Keep modules narrowly scoped
  • DRY: Share helpers before copy-pasting
  • Single responsibility: Split files when concerns diverge
  • Composable primitives: Prefer signals, hooks, utilities over deep inheritance

Need Help?