Claude Code for Windmill Dev — Workflow Guide
The Setup
You are building internal tools and workflows with Windmill, an open-source platform for scripts, flows, and apps. Windmill lets you write scripts in TypeScript, Python, Go, or Bash, chain them into workflows, and build UIs on top — all with built-in scheduling, webhooks, and approval steps. Claude Code can build internal tools, but it creates standalone Express/Flask applications instead of Windmill scripts.
What Claude Code Gets Wrong By Default
-
Builds standalone web applications. Claude creates Express servers with React dashboards for internal tools. Windmill provides the infrastructure — you write the script logic, Windmill handles the UI, scheduling, and execution.
-
Manages secrets in .env files. Claude puts API keys and database credentials in
.env. Windmill has a built-in secret management system — secrets are stored encrypted and referenced as$res:secrets/my_secretin scripts. -
Creates custom job queues. Claude sets up Redis/Bull for background job processing. Windmill is a job execution engine — scripts automatically queue, retry, and log results without custom queue infrastructure.
-
Ignores the type system for parameters. Claude writes scripts with untyped parameters. Windmill auto-generates input forms from TypeScript/Python type annotations — properly typed parameters give you free UI forms.
The CLAUDE.md Configuration
# Windmill Internal Tools
## Platform
- Tool: Windmill (open-source internal tool builder)
- Scripts: TypeScript, Python, Go, Bash
- Flows: multi-step workflows with branching
- Apps: low-code UI builder with script backends
## Windmill Rules
- Scripts: typed functions with main() export
- Resources: $res:resource_type/name for connections
- Variables: $var:name for config values
- Secrets: $res:secrets/name for API keys
- Flows: chain scripts with approval, branching, loops
- Apps: drag-and-drop UI connected to scripts
- Schedule: cron-based scheduling per script
## Conventions
- Export async function main(param: type) in TypeScript
- Type all parameters for auto-generated forms
- Use resources for database/API connections
- Flows for multi-step operations
- Return value is the script output
- Use Windmill CLI (wmill) for local development
- Sync with git: wmill sync push/pull
Workflow Example
You want to create an automated data pipeline that syncs data between two systems. Prompt Claude Code:
“Create a Windmill flow that fetches new orders from Shopify API, transforms them to match our internal format, upserts them into PostgreSQL, and sends a Slack notification with the sync summary. Use TypeScript scripts for each step.”
Claude Code should create four Windmill TypeScript scripts: a Shopify fetch script using $res:shopify/api_key, a transform script with typed input/output, a PostgreSQL upsert script using $res:postgresql/connection, and a Slack notification script. Then define a flow that chains them with error handling.
Common Pitfalls
-
Not using resources for connections. Claude hardcodes database URLs and API keys in script code. Windmill resources provide centralized connection management with encrypted storage — scripts reference resources, not raw credentials.
-
Ignoring type annotations for UI. Claude writes
function main(data: any). Windmill generates input forms from type annotations —function main(email: string, count: number)automatically creates a form with text input and number input fields. -
Building custom error handling. Claude wraps everything in try-catch with custom logging. Windmill captures script output, errors, and execution time automatically. Let errors propagate — Windmill logs them and can trigger retry or notification flows.