internal: Improve instructions for claude (#7921)

* Improve CLAUDE.md instructions and compact DB schema summary

- Add code validation instructions (cargo check, npm run check) to all
  CLAUDE.md files with guidance to use only relevant feature flags
- Reference backend/CLAUDE.md and frontend/CLAUDE.md paths from root
- Add database querying guidance (psql commands for exact table info)
- Compact summarize_schema.py output: inline columns, shorten types,
  one-line enums, drop indexes (use psql \d for exact info)
- Fix FK parsing for multi-line ALTER TABLE statements
- Result: schema summary reduced from 1514 lines/40KB to 194 lines/23KB

* cleaning

* fix: use prefix-based type abbreviations and filter CONSTRAINT pseudo-columns

- Change TYPE_ABBREVIATIONS matching from exact to prefix-based so
  parametrized types (character(64) -> char(64)) and array types
  (integer[] -> int[], real[] -> float[]) are properly abbreviated
- Skip CONSTRAINT lines inside CREATE TABLE blocks that were being
  incorrectly matched as columns by the column regex
- Update summarized_schema.txt to reflect both changes

Co-authored-by: centdix <centdix@users.noreply.github.com>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: centdix <centdix@users.noreply.github.com>
This commit is contained in:
centdix
2026-02-12 08:19:44 +01:00
committed by GitHub
parent 7e3f81605a
commit 2dad2b43a4
6 changed files with 313 additions and 1129 deletions

View File

@@ -1,8 +1,8 @@
---
description:
globs: frontend/src/**/*.svelte
alwaysApply: false
name: svelte-frontend
description: Svelte coding guidelines for the Windmill frontend. MUST use when writing or modifying code in the frontend directory.
---
# Svelte 5 Best Practices
This guide outlines best practices for developing with Svelte 5, incorporating the new Runes API and other modern Svelte features. These rules MUST NOT be applied on svelte 4 files unless explicitly asked to do so.

View File

@@ -17,19 +17,32 @@ When implementing new features in Windmill, follow these best practices:
## Language-Specific Guides
- Backend (Rust): @backend/rust-best-practices.mdc + @backend/summarized_schema.txt
- Frontend (Svelte 5): @frontend/svelte5-best-practices.mdc
- Backend (Rust): see `backend/CLAUDE.md` and the `rust-backend` skill: `.claude/skills/rust-backend/SKILL.md`
- Frontend (Svelte 5): see `frontend/CLAUDE.md` and the `svelte-frontend` skill: `.claude/skills/svelte-frontend/SKILL.md`
## Code Validation (MUST DO)
After making code changes, you MUST run the appropriate checks and fix all errors before considering the work done:
- **Backend**: Run `cargo check` from the `backend/` directory. Only enable the feature flags needed for the code you changed — check `backend/Cargo.toml` `[features]` section to identify which flags gate the crates/modules you modified. For example: `cargo check --features enterprise,parquet` if you only touched enterprise and parquet code.
- **Frontend**: Run `npm run check` from the `frontend/` directory.
## Querying the Database
To query the database directly, use psql with the following connection string:
`backend/summarized_schema.txt` provides a compact overview of all tables, columns, types, ENUMs, and foreign keys. Use it to quickly understand the data model and relationships. Note: this file is a simplified summary — it omits indexes, constraints details, and other metadata.
For exact table definitions (indexes, constraints, column defaults, etc.), query the database directly:
```bash
psql postgres://postgres:changeme@localhost:5432/windmill
```
This can be helpful for:
Useful psql commands:
- `\d <table_name>` — full table definition with indexes and constraints
- `\di <table_name>*` — list indexes for a table
- `\d+ <table_name>` — extended table info including storage and descriptions
This is also helpful for:
- Inspecting database state during development
- Testing queries before implementing them in Rust
- Debugging data-related issues

View File

@@ -49,6 +49,24 @@ Windmill uses a workspace-based architecture with multiple crates:
- Use feature flags: `#[cfg(feature = "enterprise")]`
- Isolate enterprise code in separate modules
## Code Validation (MUST DO)
After making backend changes, you MUST run `cargo check` and fix all errors and warnings before considering the work done.
Only enable the feature flags relevant to your changes — do NOT use `all_sqlx_features` as it compiles the entire codebase and is very slow. Check the `[features]` section in `Cargo.toml` to identify which flags gate the crates/modules you modified.
Examples:
```bash
# Changed core code (no feature-gated modules)
cargo check
# Changed code behind the enterprise feature
cargo check --features enterprise
# Changed kafka trigger code
cargo check --features kafka
```
## Git Workflow
- **Never push directly to main** — always create a branch and open a pull request

View File

@@ -1,6 +1,6 @@
# This script is used to summarize the database schema.
# You can use pg_dump to dump the schema to a file.
# pg_dump --file "schema.sql" --host "localhost" --port "5432" --username "postgres" --no-password --format=c --large-objects --schema-only --no-owner --no-privileges --no-tablespaces --no-unlogged-table-data --no-comments --no-publications --no-subscriptions --no-security-labels --no-toast-compression --no-table-access-method --verbose --schema "public" "windmill"
# pg_dump --file "schema.sql" --format=p --large-objects --schema-only --no-owner --no-privileges --no-tablespaces --no-unlogged-table-data --no-comments --no-publications --no-subscriptions --no-security-labels --no-toast-compression --no-table-access-method --verbose --schema "public" "postgresql://postgres:changeme@localhost:5432/windmill"
# Then you can run python summarize_schema.py schema.sql to get the summarized schema.
import re
@@ -17,6 +17,7 @@ def summarize_schema(file_path):
# Use state variables to parse multi-line definitions
current_table = None
current_enum = None
pending_alter_table = None # For multi-line ALTER TABLE ... ADD CONSTRAINT
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
@@ -54,6 +55,9 @@ def summarize_schema(file_path):
match_column = re.match(r'^"?(\w+)"?\s+([\w\d\.\[\]\(\)]+)', line)
if match_column:
col_name = match_column.group(1)
# Skip CONSTRAINT definitions (e.g., CHECK, UNIQUE) mistakenly matched as columns
if col_name.upper() == 'CONSTRAINT':
continue
col_type = match_column.group(2)
tables[current_table]['columns'].append(f"{col_name} ({col_type})")
@@ -65,16 +69,22 @@ def summarize_schema(file_path):
tables[current_table]['pks'].update(pk_cols)
continue
# --- Parse Foreign Keys (defined outside CREATE TABLE) ---
match_fk = re.match(r"ALTER TABLE ONLY public\.(\w+)\s+ADD CONSTRAINT \w+ FOREIGN KEY \(([\w,\s\"]+)\) REFERENCES public\.(\w+)\(([\w,\s\"]+)\);", line)
if match_fk:
from_table, from_cols, to_table, to_cols = match_fk.groups()
# Clean up column names
from_cols_clean = ', '.join([c.strip().strip('"') for c in from_cols.split(',')])
to_cols_clean = ', '.join([c.strip().strip('"') for c in to_cols.split(',')])
fk_string = f"({from_cols_clean}) -> {to_table}({to_cols_clean})"
tables[from_table]['fks'].append(fk_string)
# --- Parse Foreign Keys (defined outside CREATE TABLE, may span 2 lines) ---
match_alter = re.match(r"ALTER TABLE ONLY public\.(\w+)$", line)
if match_alter:
pending_alter_table = match_alter.group(1)
continue
if pending_alter_table:
match_fk = re.match(r"ADD CONSTRAINT \w+ FOREIGN KEY \(([\w,\s\"]+)\) REFERENCES public\.(\w+)\(([\w,\s\"]+)\)", line)
if match_fk:
from_cols, to_table, to_cols = match_fk.groups()
from_cols_clean = ', '.join([c.strip().strip('"') for c in from_cols.split(',')])
to_cols_clean = ', '.join([c.strip().strip('"') for c in to_cols.split(',')])
fk_string = f"({from_cols_clean}) -> {to_table}({to_cols_clean})"
tables[pending_alter_table]['fks'].append(fk_string)
pending_alter_table = None
continue
# --- Parse Index definitions ---
match_index = re.match(r"CREATE (UNIQUE )?INDEX (\w+) ON public\.(\w+) USING (\w+) \((.+)\);", line)
@@ -94,44 +104,73 @@ def summarize_schema(file_path):
return enums, tables
TYPE_ABBREVIATIONS = {
'character': 'char',
'integer': 'int',
'bigint': 'bigint',
'smallint': 'smallint',
'boolean': 'bool',
'timestamp': 'ts',
'bytea': 'bytes',
'real': 'float',
'json': 'json',
'jsonb': 'jsonb',
'text': 'text',
'uuid': 'uuid',
'bit(64)': 'bit64',
}
def shorten_type(col_str):
"""Shorten a 'name (type)' string to 'name(short_type)'."""
match = re.match(r'^(\w+) \((.+)\)$', col_str)
if not match:
return col_str
name, typ = match.group(1), match.group(2)
# Strip public. prefix from enum types
typ = re.sub(r'^public\.', '', typ)
# Apply abbreviations (prefix-based to handle parametrized types like character(64) and array types like integer[])
for prefix, abbr in TYPE_ABBREVIATIONS.items():
if typ.startswith(prefix):
typ = abbr + typ[len(prefix):]
break
return f"{name}({typ})"
def format_output(enums, tables):
"""
Formats the parsed schema data into a clean, readable string.
Formats the parsed schema data into a compact, LLM-friendly string.
"""
output = []
output.append("### Simplified Database Schema ###")
output.append("\n--- Custom Data Types (ENUMs) ---\n")
output.append("# Database Schema")
output.append("")
output.append("## ENUMs")
if not enums:
output.append("No custom ENUM types found.")
output.append("(none)")
else:
for name, values in sorted(enums.items()):
output.append(f"{name}:")
for v in values:
output.append(f" - {v}")
output.append("")
output.append(f"{name}: {', '.join(values)}")
output.append("\n--- Tables and Relationships ---\n")
output.append("")
output.append("## Tables")
if not tables:
output.append("No tables found.")
output.append("(none)")
else:
for name, data in sorted(tables.items()):
output.append(f"TABLE: {name}")
# Columns: inline, comma-separated, with PK marker and shortened types
cols = []
for col in data['columns']:
col_short = shorten_type(col)
col_name = col.split(' ')[0]
marker = " (PK)" if col_name in data['pks'] else ""
output.append(f" - {col}{marker}")
if col_name in data['pks']:
col_short += " PK"
cols.append(col_short)
output.append(f"{name}: {', '.join(cols)}")
# Foreign keys on one indented line
if data['fks']:
output.append(" Relationships:")
for fk in data['fks']:
output.append(f" - {fk}")
if data['indexes']:
output.append(" Indexes:")
for idx in data['indexes']:
output.append(f" - {idx}")
output.append("-" * 20)
output.append(f" FK: {' | '.join(data['fks'])}")
# Indexes omitted for brevity — query the database for exact index info
return "\n".join(output)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
## Core Principles
- Follow @svelte5-best-practices.mdc for detailed guidelines
- Follow the `svelte-frontend` skill for best practices: .claude/skills/svelte-frontend/SKILL.md
- Use Runes ($state, $derived, $effect) for reactivity
- Keep components small and focused
- Always use keys in {#each} blocks
@@ -93,6 +93,14 @@ The `resource()` utility:
- Form components (TextInputs, ToggleButtons, Select ...) should all use the same size when put together, using the unified size system.
- Read carefully components props JSDoc before using them
## Code Validation (MUST DO)
After making frontend changes, you MUST run the following and fix all errors and warnings before considering the work done:
```bash
npm run check
```
## Backend API
- If you need to call the backend API, you can find the available routes in ../backend/windmill-api/openapi.yaml