export declare const WORKFLOW_RULES = "Follow these rules strictly when generating workflows:\n\n1. **Always use newCredential() for authentication**\n - When a node needs credentials, always use `newCredential('Name')` in the credentials config\n - NEVER use placeholder strings, fake API keys, or hardcoded auth values\n - Never synthesize credential IDs. Do not invent raw IDs such as `WHATSAPP_CREDENTIAL_ID`, `mock-gmail-oauth2`, or any `mock-*` value\n - If `availableCredentials` is provided, treat it as an allow-list: copy an existing credential ID exactly or use `newCredential('Name')` without an ID\n - Example: `credentials: { slackApi: newCredential('Slack Bot') }`\n - The credential type must match what the node expects\n\n2. **Trust empty item lists \u2014 don't synthesize fake items**\n - When a query returns 0 items, downstream nodes simply don't run for that execution. For scheduled or polling triggers this is the correct \"nothing to do this round\" signal \u2014 the next run will execute normally when data appears.\n - DO NOT add `alwaysOutputData: true` just to \"keep the chain alive.\" Forcing an empty `{}` item downstream is what causes `undefined` reads, failed HTTP calls to `GET undefined`, and Code-node crashes on missing fields.\n - DO NOT add an IF gate before a loop to check \"has items?\" \u2014 loops (`splitInBatches`, per-item nodes, `filter`) already no-op on empty input. The gate is redundant and adds a failure surface.\n - `alwaysOutputData: true` is only correct when you specifically need a downstream branch to run on the \"empty\" case \u2014 e.g. a dedicated \"no matches found\" notification path. In that case, pair it with an `IF` that explicitly checks for the empty case and routes accordingly. Never use it as a default.\n - To drop invalid items mid-pipeline, use a `filter` node. A `filter` that rejects everything emits 0 items and the chain correctly stops \u2014 no `IF` + `splitInBatches` composition needed.\n\n3. **Use `executeOnce: true` for single-execution nodes**\n - When a node receives N items but should only execute once (not N times), set `executeOnce: true`\n - Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution\n - If a node fetches shared context independently but is chained after a multi-item source, set `executeOnce: true` so it does not run once per incoming item\n - Duplicate notifications, duplicate API calls, or repeated shared-context fetches usually mean a downstream node is missing `executeOnce: true` or should be on a parallel branch\n - Example: `config: { ..., executeOnce: true }`\n\n4. **Pick the right control-flow primitive**\n - **Per-item loop with side effects (fetch, embed, write)** \u2192 `splitInBatches` with `batchSize: 1` feeding the per-item work, loop back via `nextBatch`. No `IF` gate before it.\n - **Drop items that don't match a predicate** \u2192 `filter`. It emits 0 items when nothing matches, and the chain stops cleanly.\n - **Two mutually exclusive paths that both do real work** \u2192 `IF` (`onTrue` / `onFalse`).\n - **Many mutually exclusive paths keyed off a value** \u2192 `switch` (`onCase`).\n - A Filter or IF only selects items; it does not perform a requested side effect. If the user asks to archive, update, delete, send, or create only matching items, wire the corresponding action node on the matching path.\n - Nested control flow is supported: `ifNode.onTrue(loopBuilder)`, `switchNode.onCase(0, loopBuilder)`, and `splitInBatches(sib).onEachBatch(ifElseBuilder)` all compile and wire correctly. Use them when the semantics genuinely call for it, not as a workaround for empty-list handling.\n\n5. **Input and output indices are 0-based \u2014 `.input(0)` is the FIRST input**\n - `.input(0)` and `.output(0)` refer to the **first** input/output. `.input(1)` and `.output(1)` refer to the **second**. `.input(1)` is NOT the first input \u2014 it is the second one.\n - This applies everywhere indices are passed: `.input(n)`, `.output(n)`, `.onCase(n, ...)` for switch outputs, and any `outputIndex` argument.\n - When wiring N branches to a Merge node, the indices are `0, 1, ..., N-1` \u2014 never `1, 2, ..., N`.\n - Counter-examples to AVOID:\n - WRONG: `sourceA.to(merge.input(1))` followed by `sourceB.to(merge.input(2))` \u2014 this skips input 0 entirely; the first branch is silently dropped.\n - CORRECT: `sourceA.to(merge.input(0))` followed by `sourceB.to(merge.input(1))`.";