Files
windmill/CLAUDE.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

4.8 KiB

Windmill

Open-source platform for internal tools, workflows, API integrations, background jobs, and UIs. Rust backend + Svelte 5 frontend.

Workflow

  1. Understand: Before coding, use wm-ts-nav to explore (see Code Navigation below). Use outline to understand file structure, body to read specific symbols, def/callers/callees to trace code. Read docs/ for domain context.
  2. Plan: For non-trivial changes, use plan mode. For large features, break into reviewable stages
  3. Execute: Follow coding patterns from skills (rust-backend, svelte-frontend)
  4. Validate: After every change, run the appropriate checks per docs/validation.md

Documentation

  • Validation: docs/validation.md — what checks to run based on what you changed
  • Enterprise: docs/enterprise.md — EE file conventions and PR workflow
  • Backend patterns: use the rust-backend skill when writing Rust code
  • Frontend patterns: use the svelte-frontend skill when writing Svelte code. Do NOT edit svelte files unless you have read that skill.
  • Code review: use /local-review to review a PR for bugs and CLAUDE.md compliance
  • Domain guides: .claude/skills/native-trigger/ and frontend/tutorial-system-guide.mdc
  • Brand/UI guidelines: frontend/brand-guidelines.md

Dev Environment

  • Backend: cargo run from backend/ (API at http://localhost:8000)
  • Frontend: REMOTE=http://localhost:8000 npm run dev from frontend/ (port 3000+)
  • DB: psql postgres://postgres:changeme@localhost:5432/windmill
  • Login: admin@windmill.dev / changeme
  • Instance settings: navigate to /#superadmin-settings

Banned Patterns

$bindable(default_value) on optional props

Using $bindable(default_value) on props that can be undefined is banned. This pattern causes subtle bugs because the default value masks the undefined state.

Bad:

let { my_prop = $bindable(default_value) }: { my_prop?: string } = $props()

Correct alternatives:

  1. Use $derived with nullish coalescing — handle the potential undefined at the usage site:

    let { my_prop = $bindable() }: { my_prop?: string } = $props()
    let effective_value = $derived(my_prop ?? default_value)
    
  2. Create a useMyPropState() helper — encapsulate the undefined-handling logic in a reusable function and call it higher in the component tree, so the child component always receives a defined value.

Code Navigation

wm-ts-nav is an AST-aware code navigator. Use Grep for regex/pattern search. Use wm-ts-nav for structural queries — it skips comments/strings and understands symbol boundaries.

Prefer wm-ts-nav over Read to save context window:

  • outline <file> instead of reading a full file — understand structure first, then body or Read for specifics
  • body "X" instead of reading a full file to see one function/struct
  • refs "X" --caller instead of reading files to find which function contains each reference
  • callers "X" / callees "X" for call-graph questions
NAV="sh wm-ts-nav/nav"
# Use --root backend for Rust, --root frontend/src for TS/Svelte
$NAV --root backend outline backend/path/to/file.rs      # file structure
$NAV --root backend def "ServiceName"                     # find definition
$NAV --root backend body "decrypt_oauth_data"             # extract source code
$NAV --root backend search "%" --parent ServiceName       # methods on a type
$NAV --root backend search "Trigger" --kind struct        # find by kind
$NAV --root backend refs "X" --file handler.rs --caller   # scoped refs with caller
$NAV --root backend callers "X"                           # who calls X?
$NAV --root backend callees "X"                           # what does X call?

Limitations — syntax-level analysis, no type inference:

  • Import paths are stored literally — crate::X and super::X pointing to the same type won't be linked
  • Re-export chains (pub use) aren't followed — refs through different re-export paths won't connect
  • Trait methods can't be resolved to their trait definition
  • Nested use trees (use foo::{bar::{A, B}, baz::C}) aren't parsed correctly
  • Glob imports (use foo::*) — refs won't show import origin
  • Macro-generated symbols (e.g. sqlx::FromRow) — invisible to tree-sitter
  • Single-char identifiers — intentionally filtered out of refs
  • callees shows all identifiers in a function body, not just actual calls
  • import * as ns namespace imports — member accesses through ns.X aren't resolved

Core Principles

  • Use outline/body to explore, then Read with offset/limit from the results before editing — avoid reading full files
  • Search for existing code to reuse before writing new code
  • Follow established patterns in the codebase
  • Keep changes focused — don't refactor beyond what's asked