Files
windmill/README_WORKMUX_DEV.md
hugocasa 96229575e6 chore: dev tooling — wm-ts-nav navigator, format hooks, review skill (#8337)
* chore: remove wm-cursor, add local-review skill, update PR skill for EE

- Remove the unused wm-cursor script and all references to it in
  README_WORKMUX_DEV.md and worktree-common.sh
- Add /local-review skill for code review (bugs + CLAUDE.md compliance)
- Add EE companion PR workflow to the /pr skill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add wm-ts-nav tree-sitter navigator and fix format hooks

- Add wm-ts-nav: standalone tree-sitter code navigator with SQLite index
  for fast symbol search, definition lookup, and file outlines across
  Rust, TypeScript, and Svelte files (~12ms warm, ~1s cold for 482 files)
- Fix format hooks: surface errors instead of swallowing with 2>/dev/null,
  use direct prettier path with svelte plugin, add success feedback
- Add wm-ts-nav commands to settings allow list
- Document wm-ts-nav usage in CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(wm-ts-nav): add refs command and --parent filter

- refs: find usages of a symbol in code, skipping comments and strings
  (tree-sitter AST walk, ~46ms for 482 files vs grep's 4ms but no noise)
- --parent filter on search: find all methods on a type across all files
  (e.g. search "%" --kind function --parent ServiceName)
- Update CLAUDE.md with clearer when-to-use guidance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(wm-ts-nav): index refs in DB with import-path resolution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(wm-ts-nav): add body, callers, callees commands and refs --file/--caller

- body: extract a symbol's source code from disk using indexed line ranges
- callers: cross-file call graph via SQL join of refs + symbols tables
- callees: list all identifiers referenced within a symbol's body
- refs --file: scope results to files matching a substring
- refs --caller: annotate each ref with the containing function name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(wm-ts-nav): add auto-rebuilding wrapper script

The `wm-ts-nav/nav` wrapper checks if source files are newer than the
binary and rebuilds automatically. Invoked via `sh wm-ts-nav/nav` to
avoid needing executable permissions after clone.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: tighten CLAUDE.md nav section for actionable guidance

Remove redundant question→command mapping, latency numbers, and
excessive examples. Lead with "prefer wm-ts-nav over Read to save
context window" and keep only the patterns that change behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: revert backend/Cargo.lock to main

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: promote wm-ts-nav in workflow, copy binary to worktrees

- CLAUDE.md: integrate wm-ts-nav into Workflow step 1 and Core
  Principles so agents use outline/body before full file reads
- workmux: copy built binary via files.copy
- worktree-common.sh: copy binary in wm_copy_dependencies for webmux

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(wm-ts-nav): fix double indexing, add TSX grammar, remove needless clone

- Reuse index stats from the pre-query update instead of indexing twice
  on the Index command
- Add Lang::Tsx variant so .tsx/.jsx files use LANGUAGE_TSX instead of
  LANGUAGE_TYPESCRIPT (Svelte stays on TS since script blocks are pure TS)
- Remove source.clone() for non-Svelte files — move directly instead

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(wm-ts-nav): fix svelte line numbers, add class methods, innermost caller

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:07:49 +00:00

212 lines
5.9 KiB
Markdown

# Windmill Development with workmux
This guide covers the workmux-based development setup for Windmill. Each worktree gets its own tmux window with a Claude Code agent, a backend server (with auto-reload), and a frontend dev server — all on isolated ports.
## Prerequisites
- tmux
- Rust toolchain (rustup)
- Node.js + npm
- PostgreSQL running locally (see `backend/.env`)
## Installation
### 1. Install workmux
```bash
cargo install workmux
```
### 2. Install the Claude Code plugin
```bash
workmux claude install
```
This lets workmux manage Claude Code agents in worktree panes.
### 3. Install cargo-watch
Used for auto-recompiling the backend on file changes:
```bash
cargo install cargo-watch
```
### 4. Install llm CLI (required for auto branch naming)
workmux uses the `llm` CLI to automatically generate branch names from prompts. Install it with:
```bash
uv tool install llm
llm install llm-anthropic
```
Then set your Anthropic API key:
```bash
llm keys set anthropic
# paste your API key when prompted
```
### 5. Recommended: shell alias and autocomplete
Set up a `wm` alias for convenience:
```bash
# Add to your ~/.zshrc
alias wm="workmux"
```
Setting up zsh autocomplete is also recommended — see the [workmux docs](https://github.com/rubenfiszel/workmux) for instructions.
## Port Slot System
Each worktree is assigned a **slot** that determines its ports:
| Slot | Backend | Frontend |
| ---- | ------- | -------- |
| 0 | 8000 | 3000 |
| 1 | 8010 | 3010 |
| 2 | 8020 | 3020 |
| 3 | 8030 | 3030 |
| ... | ... | ... |
- **Slot 0** is reserved for the main worktree (default `cargo run` / `npm run dev`).
- Without `WM_SLOT`, the script auto-assigns the first available slot (starting from 1) and prints it.
- With `WM_SLOT=N`, it uses that slot and errors if the ports are taken.
## SSH Port Forwarding
If you develop over SSH, add this to `~/.ssh/config` on your **local machine** to pre-configure tunnels for each slot:
```
Host windmill-dev
HostName <remote-ip>
User <username>
# Slot 0 (main worktree)
LocalForward 8000 localhost:8000
LocalForward 3000 localhost:3000
# Slot 1
LocalForward 8010 localhost:8010
LocalForward 3010 localhost:3010
# Slot 2
LocalForward 8020 localhost:8020
LocalForward 3020 localhost:3020
# Slot 3
LocalForward 8030 localhost:8030
LocalForward 3030 localhost:3030
```
Then connect once and all tunnels are active:
```bash
ssh windmill-dev
```
Access the frontend at `http://localhost:<frontend-port>` in your local browser.
## Quickstart
```bash
# Create a new worktree (auto-assigns slot, prints ports)
workmux add my-feature
# Or with an explicit slot
WM_SLOT=2 workmux add my-feature
# Create a worktree and immediately send a prompt to the agent
workmux add -A -p "fix the login bug in auth.rs"
```
The `add` command creates the worktree but does **not** open it. To open the tmux window and start working:
```bash
workmux open my-feature
```
This will open a tmux window with three panes:
- **Claude Code agent** (focused)
- **Backend**: `cargo watch -x run` on the assigned port (auto-reloads on save)
- **Frontend**: `npm run dev` proxying to the backend
When using `-A` with `add`, the worktree is created and opened automatically, and the prompt is sent to the agent right away.
Check which ports were assigned:
```bash
cat <worktree-path>/.env.local
```
### Sending work to the agent
```bash
# Send a prompt to the agent in a worktree
workmux send my-feature "fix the login bug in auth.rs"
# Check agent status
workmux status
```
### Merging and cleaning up
We never merge worktrees directly — always create a PR on GitHub and let it be merged there. Once the PR is merged, clean up the worktree:
```bash
# Close the tmux window but keep the worktree
workmux close my-feature
# After your PR is merged, remove the worktree, branch, and tmux window
workmux rm my-feature
```
> **Note**: Do not use `workmux merge`. Always go through a PR to get your changes into main. You can ask the Claude Code agent in the worktree to create the PR for you.
## Configuration
The setup is defined in `.workmux.yaml` at the repo root. Key sections:
- **`post_create`**: Runs `scripts/worktree-env` to generate `.env.local` with port assignments
- **`panes`**: Defines the tmux layout (agent, backend, frontend)
- **`files.copy`**: Copies `backend/.env` and `scripts/` into each worktree
The `post_create` hook also copies `frontend/node_modules` using `cp -a` (preserves `.bin/` symlinks that `cp -r` would dereference).
## Enterprise (EE) Code Access
The enterprise source code lives in the `windmill-ee-private` repository (sibling to this repo). When you create a worktree, `scripts/worktree-env` automatically creates a matching EE worktree on the same branch and configures Claude Code's `additionalDirectories` to grant access.
### Sandbox setup
When using sandbox mode, the container needs explicit mounts to access the EE repo. Add the following to your global workmux config (`~/.config/workmux/config.yaml`):
```yaml
sandbox:
extra_mounts:
- host_path: ~/windmill-ee-private
writable: true
- host_path: ~/windmill-ee-private__worktrees
writable: true
```
This mounts both the main EE repo (used by the main worktree) and the EE worktrees directory (used by feature worktrees) into every sandbox container.
## Cargo Features
To build the backend with specific Cargo features (e.g., `enterprise`, `parquet`), pass them via `CARGO_FEATURES`. The backend pane reads this from `.env.local` and appends `--features <value>` to the `cargo watch` command.
**With `wm` (workmux):**
Set `CARGO_FEATURES` as an environment variable before creating the worktree:
```bash
CARGO_FEATURES="enterprise,parquet" wm add my-feature
```
This gets written to `.env.local` by the `post_create` hook (`scripts/worktree-env`), and the backend pane picks it up automatically.
## Login
Default credentials: `admin@windmill.dev` / `changeme`