Compare commits

..

3 Commits

Author SHA1 Message Date
centdix
90782336c8 remove rust plugin 2026-03-02 14:23:31 +01:00
centdix
b121f4388b docs: move autonomous-mode reference to system prompt (#8173)
* docs: move autonomous-mode reference from CLAUDE.md to system prompt

Remove the autonomous-mode.md bullet from CLAUDE.md and instead reference
it via the workmux system prompt, matching the workmux-web pattern. Also
remove the duplicated "Dev Environment (tmux)" section from
autonomous-mode.md since that info is already in the system prompt.

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

* docs: add autonomous-mode.md reference to wmdev sandbox system prompt

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:43:19 +00:00
HugoCasa
5ebaa43aa1 internal(workmux): allow cloning main db using WM_CLONE_DB or --clone-db 2026-03-02 11:18:36 +01:00
17 changed files with 36 additions and 150 deletions

View File

@@ -110,7 +110,6 @@
]
},
"enabledPlugins": {
"rust-analyzer-lsp@claude-plugins-official": true,
"typescript-lsp@claude-plugins-official": true,
"code-review@claude-plugins-official": true
}

View File

@@ -99,6 +99,8 @@ profiles:
5) Include in PR descriptions using markdown image syntax.
IMPORTANT: Read docs/autonomous-mode.md before starting any work.
linkedRepos:
- repo: windmill-labs/windmill-ee-private
alias: ee

View File

@@ -55,7 +55,8 @@ panes:
- Pane 2: frontend (npm run dev)\n\n
To check logs, use: \`tmux capture-pane -t .1 -p -S -50\` (backend) or \`tmux capture-pane -t .2 -p -S -50\` (frontend).\n
When restarting backend or frontend, make sure to use the ports listed in .env.local.\n
Because we are running backend with cargo watch, to verify your changes, just check the logs in the backend pane. No need for cargo check."
Because we are running backend with cargo watch, to verify your changes, just check the logs in the backend pane. No need for cargo check.\n\n
IMPORTANT: Read docs/autonomous-mode.md before starting any work."
focus: true
- command: 'ROOT="$(git rev-parse --show-toplevel)"; [ -f "$ROOT/.env.local" ] && source "$ROOT/.env.local"; cd "$ROOT/backend" && PORT=${BACKEND_PORT:-8000} cargo watch -x "run ${CARGO_FEATURES:+--features $CARGO_FEATURES}"'
split: horizontal

View File

@@ -12,7 +12,6 @@ Open-source platform for internal tools, workflows, API integrations, background
## Documentation
- **Validation**: `docs/validation.md` — what checks to run based on what you changed
- **Autonomous mode**: `docs/autonomous-mode.md` — when running in bypass/auto permission mode
- **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

View File

@@ -39,26 +39,6 @@ Even in bypass mode, **enter plan mode before starting non-trivial work**. Ask a
- Read `docs/validation.md` to know what checks you'll need to run
- Break large features into stages — commit each stage separately
## Dev Environment (tmux)
Backend and frontend are running in tmux panes in the current session:
- **Pane 0**: This pane (Claude agent)
- **Pane 1**: Backend (`cargo watch -x run`)
- **Pane 2**: Frontend (`npm run dev`)
### Checking Logs
```bash
# Backend logs (last 50 lines)
tmux capture-pane -t .1 -p -S -50
# Frontend logs (last 50 lines)
tmux capture-pane -t .2 -p -S -50
```
Backend runs with `cargo watch`, so Rust changes auto-recompile — just check pane 1 logs for errors. No need to run `cargo check` separately during iteration if the backend pane shows a successful build.
## Manual Testing
After code changes compile and type-check, verify the feature works:

View File

@@ -13,9 +13,6 @@ export async function initFlow(
flowStateStore: StateStore<FlowState>
) {
await initFlowState(flow, flowStateStore)
if (flow.value && !flow.value.node_offsets) {
flow.value.node_offsets = {}
}
flowStore.val = flow
}

View File

@@ -137,7 +137,6 @@
const flowGraphContext = getGraphContext()
const diffManager = flowGraphContext?.diffManager
const moveManager = flowGraphContext?.moveManager
const freeDrag = flowGraphContext?.freeDrag
let pickableIds: Record<string, any> | undefined = $state(undefined)
@@ -322,13 +321,7 @@
style="width: 275px; height: 34px;"
onmouseenter={() => (hover = true)}
onmouseleave={() => (hover = false)}
onpointerdown={(e) => {
if (!$freeDrag) {
e.stopPropagation()
e.preventDefault()
}
dispatch('pointerdown', e)
}}
onpointerdown={stopPropagation(preventDefault((e) => dispatch('pointerdown', e)))}
>
{#if id}
<DiffActionBar moduleId={id} {moduleAction} {diffManager} {flowStore} />

View File

@@ -465,18 +465,6 @@
modules={flowStore.val.value.modules}
{noteMode}
notes={flowStore.val.value.notes}
nodeOffsets={flowStore.val.value.node_offsets}
onNodeOffsetUpdate={(nodeId, offset) => {
if (!flowStore.val.value.node_offsets) {
flowStore.val.value.node_offsets = {}
}
flowStore.val.value.node_offsets[nodeId] = offset
refreshStateStore(flowStore)
}}
onNodeOffsetsReset={() => {
flowStore.val.value.node_offsets = {}
refreshStateStore(flowStore)
}}
preprocessorModule={flowStore.val.value?.preprocessor_module}
failureModule={flowStore.val.value?.failure_module}
currentInputSchema={flowStore.val.schema}

View File

@@ -76,7 +76,7 @@ export function filteredContentForExport(flow: ExtendedOpenFlow) {
let o = {
summary: flow.summary,
description: flow.description,
value: $state.snapshot(flow.value),
value: flow.value,
schema: flow.schema
}
if (flow.dedicated_worker) {

View File

@@ -37,7 +37,7 @@
import BaseEdge from './renderers/edges/BaseEdge.svelte'
import EmptyEdge from './renderers/edges/EmptyEdge.svelte'
import { sugiyama, dagStratify, coordCenter, decrossTwoLayer, decrossOpt } from 'd3-dag'
import { Expand, MousePointer, Hand, RotateCcw } from 'lucide-svelte'
import { Expand, MousePointer, Hand } from 'lucide-svelte'
import Toggle from '../Toggle.svelte'
import DataflowEdge from './renderers/edges/DataflowEdge.svelte'
import { encodeState, readFieldsRecursively, getModifierKey, isMac } from '$lib/utils'
@@ -81,7 +81,6 @@
let useDataflow: Writable<boolean | undefined> = writable<boolean | undefined>(false)
let showAssets: Writable<boolean | undefined> = writable<boolean | undefined>(true)
let freeDrag: Writable<boolean> = writable<boolean>(false)
let showNotes = $state(true)
const triggerContext = getContext<TriggerContext>('TriggerContext')
@@ -130,9 +129,6 @@
suspendStatus?: Record<string, { job: Job; nb: number }>
noteMode?: boolean
notes?: FlowNote[]
nodeOffsets?: Record<string, { x: number; y: number }>
onNodeOffsetUpdate?: (nodeId: string, offset: { x: number; y: number }) => void
onNodeOffsetsReset?: () => void
chatInputEnabled?: boolean
multiSelectEnabled?: boolean
onDelete?: (id: string) => void
@@ -226,9 +222,6 @@
flowHasChanged = false,
noteMode = false,
notes = undefined,
nodeOffsets = undefined,
onNodeOffsetUpdate = undefined,
onNodeOffsetsReset = undefined,
exitNoteMode = undefined,
onNotePositionUpdate = undefined,
chatInputEnabled = false,
@@ -287,7 +280,6 @@
selectionManager: selectionManager,
useDataflow,
showAssets,
freeDrag,
noteManager,
moveManager,
clearFlowSelection,
@@ -522,26 +514,6 @@
let nodes = $state.raw<Node[]>([])
let edges = $state.raw<Edge[]>([])
// Track layout-computed positions (before user offsets) for drag offset computation
let layoutPositions: Record<string, { x: number; y: number }> = {}
const DRAGGABLE_NODE_TYPES = new Set([
'module',
'forLoopStart',
'forLoopEnd',
'branchAllStart',
'branchAllEnd',
'branchOneStart',
'branchOneEnd',
'whileLoopStart',
'whileLoopEnd',
'noBranch',
'subflowBound',
'input2',
'result',
'trigger'
])
let height = $state(0)
// Derived nodes with yOffset applied to all nodes uniformly and selectable flag set to false if notSelectable is true
@@ -670,28 +642,6 @@
}))
}
// Capture layout positions (after all spacing, before user offsets)
for (const n of finalNodes) {
if (n.type && DRAGGABLE_NODE_TYPES.has(n.type)) {
layoutPositions[n.id] = { x: n.position.x, y: n.position.y }
}
}
// Apply user-defined node offsets and set draggable flag
if (nodeOffsets || editMode) {
finalNodes = finalNodes.map((n) => {
const isDraggable = n.type != null && DRAGGABLE_NODE_TYPES.has(n.type)
const offset = nodeOffsets?.[n.id]
return {
...n,
position: offset
? { x: n.position.x + offset.x, y: n.position.y + offset.y }
: n.position,
draggable: isDraggable && editMode
}
})
}
// update nodes
nodes = [...finalNodes, ...(noteNodesResult?.noteNodes ?? [])]
@@ -814,10 +764,9 @@
$showAssets && Object.values(nodes).every((n) => n.type !== 'asset')
)
let hideNotesToggle = $derived(!notes || notes.length === 0)
let hasNodeOffsets = $derived(nodeOffsets && Object.keys(nodeOffsets).length > 0)
$effect(() => {
;[graph, allowSimplifiedPoll, $showAssets, showNotes, noteManager.renderCount, nodeOffsets]
;[graph, allowSimplifiedPoll, $showAssets, showNotes, noteManager.renderCount]
untrack(async () => {
await updateStores()
})
@@ -985,23 +934,13 @@
paneContextMenu?.onPaneContextMenu(event)
}}
onnodedragstop={(event) => {
for (const node of event.nodes) {
if (node.type === 'note') {
const positionWithOffset = {
x: node.position.x,
y: node.position.y - yOffset
}
onNotePositionUpdate?.(node.id, positionWithOffset)
} else if (node.type && DRAGGABLE_NODE_TYPES.has(node.type)) {
const layoutPos = layoutPositions[node.id]
if (layoutPos && onNodeOffsetUpdate) {
const offset = {
x: node.position.x - layoutPos.x,
y: node.position.y - yOffset - layoutPos.y
}
onNodeOffsetUpdate(node.id, offset)
}
const node = event.targetNode
if (node && node.type === 'note') {
const positionWithOffset = {
x: node.position.x,
y: node.position.y - yOffset
}
onNotePositionUpdate?.(node.id, positionWithOffset)
}
}}
onmove={(event, viewport) => {
@@ -1028,7 +967,7 @@
elevateNodesOnSelect={false}
{proOptions}
multiSelectionKey={'Shift'}
nodesDraggable={$freeDrag || false}
nodesDraggable={false}
--background-color={false}
>
<div class="absolute inset-0 !bg-surface-secondary h-full" id="flow-graph-v2"></div>
@@ -1128,18 +1067,6 @@
{#if showDataflow}
<Toggle bind:checked={$useDataflow} size="xs" options={{ right: 'Dataflow' }} />
{/if}
{#if editMode}
<Toggle bind:checked={$freeDrag} size="xs" options={{ right: 'Free drag' }} />
{/if}
{#if editMode && hasNodeOffsets}
<button
class="flex items-center gap-1 text-xs text-secondary hover:text-primary transition-colors"
onclick={() => onNodeOffsetsReset?.()}
>
<RotateCcw size={12} />
Reset layout
</button>
{/if}
</Controls>
{/if}
</SvelteFlow>

View File

@@ -38,7 +38,6 @@
selectionManager: new SelectionManager(),
useDataflow: writable(false),
showAssets: writable(false),
freeDrag: writable(false),
diffManager: createFlowDiffManager()
})

View File

@@ -9,7 +9,6 @@ export type GraphContext = {
selectionManager: SelectionManager
useDataflow: Writable<boolean | undefined>
showAssets: Writable<boolean | undefined>
freeDrag: Writable<boolean>
noteManager?: NoteManager
moveManager?: MoveManager
clearFlowSelection?: () => void

View File

@@ -63,7 +63,7 @@
const flowStore: StateStore<Flow> = $state({
val: {
summary: '',
value: { modules: [], node_offsets: {} },
value: { modules: [] },
path: '',
edited_at: '',
edited_by: '',

View File

@@ -55,7 +55,7 @@
export const flowStore: StateStore<Flow> = $state({
val: {
summary: '',
value: { modules: [], node_offsets: {} },
value: { modules: [] },
path: '',
edited_at: '',
edited_by: '',

View File

@@ -113,17 +113,6 @@ components:
description: Sticky notes attached to the flow
items:
$ref: '#/components/schemas/FlowNote'
node_offsets:
type: object
description: User-defined position offsets for flow nodes, keyed by module ID
additionalProperties:
type: object
properties:
x:
type: number
y:
type: number
required: [x, y]
required:
- modules

View File

@@ -111,7 +111,7 @@ SETTINGS
# Extracts --features <value> from args, exports CARGO_FEATURES, returns remaining args.
# Usage: parse_features_flag "$@"; set -- "${remaining_args[@]}"
parse_features_flag() {
parse_flags() {
remaining_args=()
while (( $# )); do
case $1 in
@@ -127,6 +127,10 @@ parse_features_flag() {
export CARGO_FEATURES=${1#--features=}
shift
;;
--clone-db)
export WM_CLONE_DB=1
shift
;;
*)
remaining_args+=("$1")
shift
@@ -142,7 +146,7 @@ cmd_add() {
ensure_tmux
check_dev_db
parse_features_flag "$@"
parse_flags "$@"
set -- "${remaining_args[@]}"
# Snapshot worktree list before
@@ -176,7 +180,7 @@ cmd_open() {
ensure_tmux
check_dev_db
parse_features_flag "$@"
parse_flags "$@"
set -- "${remaining_args[@]}"
# Write CARGO_FEATURES to .env.local if specified
@@ -391,6 +395,7 @@ case ${1-} in
print -u2 ""
print -u2 "Options:"
print -u2 " --features <features> Cargo features for the backend (e.g. \"enterprise,parquet\")"
print -u2 " --clone-db Clone the main 'windmill' database instead of creating an empty one"
exit 1
;;
esac

View File

@@ -61,9 +61,17 @@ if command -v psql &>/dev/null; then
if psql "$db_conn/postgres" -tc "SELECT 1 FROM pg_database WHERE datname = '${db_name}'" 2>/dev/null | grep -q 1; then
echo "Database $db_name already exists"
else
psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name}" 2>/dev/null \
&& echo "Created database $db_name" \
|| echo "WARNING: Could not create database $db_name (is PostgreSQL running?)" >&2
if [[ -n "${WM_CLONE_DB:-}" ]]; then
# Terminate active connections so CREATE DATABASE ... TEMPLATE works
psql "$db_conn/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'windmill' AND pid <> pg_backend_pid();" 2>/dev/null || true
psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name} TEMPLATE windmill" 2>/dev/null \
&& echo "Created database $db_name (template: windmill)" \
|| echo "WARNING: Could not create database $db_name from template windmill" >&2
else
psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name}" 2>/dev/null \
&& echo "Created database $db_name" \
|| echo "WARNING: Could not create database $db_name (is PostgreSQL running?)" >&2
fi
fi
db_url="${db_conn}/${db_name}?sslmode=disable"
# Run migrations against the new database