diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 4c816306b99..efb2effe479 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -377,7 +377,7 @@ jobs: - name: Install ripgrep run: command -v rg || (sudo apt-get update && sudo apt-get install -y ripgrep) - # Runs the setup CLI's Bun tests plus each workspace's Vitest suite, + # Runs the root scripts and each workspace's Vitest suite, # without `--coverage`. - name: Run tests env: diff --git a/apps/docs/content/docs/platform/enterprise/forks.mdx b/apps/docs/content/docs/platform/enterprise/forks.mdx index 4c0851c53a0..c33c941c936 100644 --- a/apps/docs/content/docs/platform/enterprise/forks.mdx +++ b/apps/docs/content/docs/platform/enterprise/forks.mdx @@ -29,7 +29,7 @@ On Sim Cloud, your organization may also need the feature turned on for your acc ### 1. Open Forks -Go to **Settings → Organization → Workspace forks** in the workspace you want to fork from (or manage). +Go to **Settings → Workspace → Workspace forks** in the workspace you want to fork from (or manage). Workspace Forks settings page showing Parent and Forks sections with Docs, See activity, and Create fork actions @@ -57,12 +57,12 @@ Everything under **Copy resources** starts **selected**. That is usually what yo Click **Fork**. The child workspace is created immediately. Deployed workflows land as **drafts** in the child. Large content (table rows, knowledge base files, file blobs) may finish copying in the background — watch **Activity** on the source workspace. - Only **deployed** workflows are forked. Drafts and undeployed work stay in the parent. If the parent has nothing deployed, the child starts with a blank starter workflow. + Only **deployed** workflows are forked, and only the ones that are [synced](#synced-workflows). Drafts and undeployed work stay in the parent. If there is nothing to copy, the child starts with a blank starter workflow. ### 3. Open the parent edge (from the child) -Open the **child** workspace → **Settings → Organization → Workspace forks**. On the **Parent** row, open the menu and choose **Edit mappings**. +Open the **child** workspace → **Settings → Workspace → Workspace forks**. On the **Parent** row, open the menu and choose **Edit mappings**. Child rows (when you are on the parent) only offer **Open workspace** and **Disconnect** — mapping and sync are owned by the child configuring how it relates to its parent. @@ -117,16 +117,35 @@ On success you will see a toast such as **Pushed to "…"** or **Pulled from " --- -## Excluded workflows +## Synced workflows -The **Excluded workflows** section on the Forks page lists this workspace's deployed workflows in their sidebar folder structure. Check a workflow — or a whole folder at once — to keep it out of forking entirely. Think of it as a `.gitignore` for syncs: +The **Synced workflows** section on the Forks page lists this workspace's deployed workflows in their sidebar folder structure, each with a checkbox. **Checked means the workflow syncs.** Uncheck one — or a whole folder at once — to keep it out of forking entirely. Think of an unchecked workflow as `.gitignore`d: - **Never sent** — pushes from this workspace do not carry it, the other side pulling from this workspace does not receive it, and creating a new fork does not copy it -- **Never touched** — a sync into this workspace will not overwrite or archive it, even if its counterpart was deleted on the other side +- **Never touched** — a sync into this workspace will not overwrite or archive it, even if its counterpart was deleted on the other side. It stays deployed and keeps serving, and a previously-synced counterpart on the other side keeps running on its last deployed version. -The setting belongs to **this workspace's copy** only. Excluding a workflow here does not exclude its counterpart in the parent or a fork — each workspace manages its own list. If the pair has synced before, the link between them is kept, so un-excluding later resumes updating the same counterpart instead of creating a duplicate. +The checkbox list belongs to **this workspace's copy** only. Unchecking a workflow here does not unsync its counterpart in the parent or a fork — each workspace manages its own list. If the pair has synced before, the link between them is kept, so re-checking later resumes updating the same counterpart instead of creating a duplicate. -**Example:** a staging fork excludes `Scratch experiment` so it can never reach production, and production excludes `Billing hotfix` so no push from staging can ever overwrite it. +On the sync page, unsynced workflows still appear in the **Deployed workflows** list, greyed out, with a tooltip naming which workspace they are unsynced in. The sync will not touch them. + +**Example:** a staging fork leaves `Scratch experiment` unchecked so it can never reach production, and production leaves `Billing hotfix` unchecked so no push from staging can ever overwrite it. + +### Sync new workflows by default + +Above the list, **Sync new workflows by default** decides where a **newly created** workflow starts: + +| Setting | A new workflow… | +|---------|-----------------| +| **Sync** (default) | joins fork sync — it arrives checked and syncs as soon as you deploy it | +| **Don't sync** | starts outside fork sync — it arrives unchecked and only syncs after you check it | + +Three things to know: + +- **It applies to the whole fork lineage.** The toggle writes every workspace in the lineage — the root, every ancestor, every descendant — so a parent and its forks can never disagree about what "new" means. Any workspace admin in the lineage can change it, and each workspace whose value changes gets its own audit entry naming the workspace the change came from. A new fork inherits the value at creation. +- **It is forward-only.** Flipping it never moves an existing workflow in or out of sync. The checkbox list above stays the record of what syncs. +- **"New" means genuinely new.** Creating, duplicating, or importing a workflow takes this setting, as does the blank starter workflow a fork gets when there is nothing to copy. A workflow that arrives as a **copy** — from a fork, or from a push or pull — ignores this setting. Only synced workflows are copied, and they always arrive synced, so a workflow you deliberately synced never lands unsynced on the other side. + +**Example:** a template workspace turns this off so every scratch workflow the team creates stays local, then checks only the handful meant to reach the forks. --- @@ -155,6 +174,8 @@ Expand a row for names of workflows and resources that were created, updated, or |--------|-----| | See Forks / create a fork | Admin on this workspace (+ feature available) | | Sync / edit mappings | Admin on **both** sides of the edge | +| Check / uncheck **Synced workflows** | Admin on the workspace those workflows live in | +| Change **Sync new workflows by default** | Admin on any one workspace in the lineage — the change applies to every member | | Rollback | Admin on the workspace the sync landed in | | Disconnect | Admin on **this** side only (you can disconnect even without access to the other workspace) | | Open the other workspace | You must be a member of that workspace | @@ -169,9 +190,9 @@ How each resource behaves at **fork** time vs **sync** time. Use this when you a | Resource | Fork | Sync | |----------|------|------| -| Deployed workflows | Copied as drafts (unless excluded) | Updated / created / archived (force overwrite) | +| Deployed workflows | Copied as drafts when [synced](#synced-workflows) | Updated / created / archived (force overwrite) | | Undeployed workflows | Not copied | Not synced | -| [Excluded workflows](#excluded-workflows) | Never | Never — not sent, not overwritten, not archived | +| [Unsynced workflows](#synced-workflows) | Never | Never — not sent, not overwritten, not archived | | Files | Optional copy (default on) | Map or copy | | File folders referenced by workflows | Mirrored with their ancestor folders, even when empty | Map by canonical path | | Tables | Optional copy (default on) | Map or copy | @@ -191,11 +212,11 @@ How each resource behaves at **fork** time vs **sync** time. Use this when you a ### Workflows -Only **deployed** workflows move. Deploy is the commit; sync is the force push/pull of those commits. Workflows marked [excluded](#excluded-workflows) never move in either direction. +Only **deployed** workflows move, and only the ones checked under [Synced workflows](#synced-workflows). An unsynced workflow never moves in either direction. | Feature | Behavior | |---|----------| -| **Fork** | Each deployed workflow becomes a **draft** in the child. Run history is not copied. Only folders that contain a copied workflow are kept. | +| **Fork** | Each synced deployed workflow becomes a **draft** in the child. Run history is not copied. Only folders that contain a copied workflow are kept. | | **Sync** | The change list shows what will be updated, created, or archived. The target is overwritten for those workflows. | **Example:** Parent has `Support triage` deployed and `WIP experiment` as a draft. The fork gets only `Support triage` as a draft. A later push updates the child from the parent’s latest deploy of `Support triage`. @@ -370,13 +391,16 @@ Schedules, webhooks, and triggers are not live in the child until you **deploy** - **Rollback ≠ undo copies** — Workflow versions roll back; copied resources can remain as orphans. - **Disconnect is permanent** — You cannot “reconnect” the same edge; you would fork again into a new workspace. - **No grandparent sync** — Only the direct parent↔child pair. +- **The sync default is lineage-wide** — **Sync new workflows by default** is one shared setting for the whole lineage, so changing it from a fork also changes it in the parent and every sibling fork. --- --- @@ -389,4 +413,4 @@ Self-hosted deployments turn Forks on with an environment variable instead of th |----------|-------------| | `FORKING_ENABLED`, `NEXT_PUBLIC_FORKING_ENABLED` | Enables workspace forking when billing is not used as the entitlement gate | -Once enabled, use the same **Settings → Organization → Workspace forks** UI as Sim Cloud. Only workspace admins can manage forks. +Once enabled, use the same **Settings → Workspace → Workspace forks** UI as Sim Cloud. Only workspace admins can manage forks. diff --git a/apps/sim/app/api/superuser/import-workflow/route.ts b/apps/sim/app/api/superuser/import-workflow/route.ts index 7ec0ceb17bf..cc59d7627bf 100644 --- a/apps/sim/app/api/superuser/import-workflow/route.ts +++ b/apps/sim/app/api/superuser/import-workflow/route.ts @@ -12,6 +12,7 @@ import { loadCopilotChatMessages } from '@/lib/mothership/chat/lifecycle' import { appendCopilotChatMessages } from '@/lib/mothership/chat/messages-store' import { verifyEffectiveSuperUser } from '@/lib/permissions/super-user' import { parseWorkflowJson } from '@/lib/workflows/operations/import-export' +import { buildNewWorkflowRow } from '@/lib/workflows/persistence/new-workflow-row' import { loadWorkflowFromNormalizedTables, saveWorkflowToNormalizedTables, @@ -129,27 +130,23 @@ export const POST = withRouteHandler(async (request: NextRequest) => { // Create new workflow record const newWorkflowId = generateId() - const now = new Date() const dedupedName = await deduplicateWorkflowName( `[Debug Import] ${sourceWorkflow.name}`, targetWorkspaceId, null ) - await db.insert(workflow).values({ - id: newWorkflowId, - userId: session.user.id, - workspaceId: targetWorkspaceId, - folderId: null, - name: dedupedName, - description: sourceWorkflow.description, - lastSynced: now, - createdAt: now, - updatedAt: now, - isDeployed: false, // Never copy deployment status - runCount: 0, - variables: sourceWorkflow.variables || {}, - }) + await db.insert(workflow).values( + await buildNewWorkflowRow(db, { + id: newWorkflowId, + userId: session.user.id, + workspaceId: targetWorkspaceId, + folderId: null, + name: dedupedName, + description: sourceWorkflow.description, + variables: sourceWorkflow.variables || {}, + }) + ) // Save using existing persistence logic const saveResult = await saveWorkflowToNormalizedTables(newWorkflowId, importedData, { diff --git a/apps/sim/app/api/v1/admin/workflows/import/route.ts b/apps/sim/app/api/v1/admin/workflows/import/route.ts index 3f4290a8b0d..0c7f0f3c405 100644 --- a/apps/sim/app/api/v1/admin/workflows/import/route.ts +++ b/apps/sim/app/api/v1/admin/workflows/import/route.ts @@ -30,6 +30,7 @@ import { adminV1ImportWorkflowContract } from '@/lib/api/contracts/v1/admin' import { parseRequest } from '@/lib/api/server' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' import { parseWorkflowJson } from '@/lib/workflows/operations/import-export' +import { buildNewWorkflowRow } from '@/lib/workflows/persistence/new-workflow-row' import { prepareWorkflowStateForPersistence } from '@/lib/workflows/persistence/prepare-state' import { saveWorkflowToNormalizedTables } from '@/lib/workflows/persistence/utils' import { deduplicateWorkflowName } from '@/lib/workflows/utils' @@ -112,23 +113,18 @@ export const POST = withRouteHandler( ) const workflowId = generateId() - const now = new Date() const dedupedName = await deduplicateWorkflowName(workflowName, workspaceId, folderId || null) - await db.insert(workflow).values({ - id: workflowId, - userId: workspaceData.ownerId, - workspaceId, - folderId: folderId || null, - name: dedupedName, - description: workflowDescription, - lastSynced: now, - createdAt: now, - updatedAt: now, - isDeployed: false, - runCount: 0, - variables: {}, - }) + await db.insert(workflow).values( + await buildNewWorkflowRow(db, { + id: workflowId, + userId: workspaceData.ownerId, + workspaceId, + folderId: folderId || null, + name: dedupedName, + description: workflowDescription, + }) + ) /** * Same normalization the editor and the v1 import API run, via the one diff --git a/apps/sim/app/api/v1/admin/workspaces/[id]/import/route.ts b/apps/sim/app/api/v1/admin/workspaces/[id]/import/route.ts index 33f94c17a08..f19a1c072a7 100644 --- a/apps/sim/app/api/v1/admin/workspaces/[id]/import/route.ts +++ b/apps/sim/app/api/v1/admin/workspaces/[id]/import/route.ts @@ -45,6 +45,7 @@ import { extractWorkflowsFromZip, parseWorkflowJson, } from '@/lib/workflows/operations/import-export' +import { buildNewWorkflowRow } from '@/lib/workflows/persistence/new-workflow-row' import { prepareWorkflowStateForPersistence } from '@/lib/workflows/persistence/prepare-state' import { saveWorkflowToNormalizedTables } from '@/lib/workflows/persistence/utils' import { deduplicateWorkflowName } from '@/lib/workflows/utils' @@ -347,23 +348,18 @@ async function importSingleWorkflow( } const workflowId = generateId() - const now = new Date() const dedupedName = await deduplicateWorkflowName(workflowName, workspaceId, targetFolderId) - await db.insert(workflow).values({ - id: workflowId, - userId: ownerId, - workspaceId, - folderId: targetFolderId, - name: dedupedName, - description: workflowData.metadata?.description || 'Imported via Admin API', - lastSynced: now, - createdAt: now, - updatedAt: now, - isDeployed: false, - runCount: 0, - variables: {}, - }) + await db.insert(workflow).values( + await buildNewWorkflowRow(db, { + id: workflowId, + userId: ownerId, + workspaceId, + folderId: targetFolderId, + name: dedupedName, + description: workflowData.metadata?.description || 'Imported via Admin API', + }) + ) /** * Same normalization the editor, the v1 import API and the single-workflow diff --git a/apps/sim/app/api/workspaces/[id]/fork/sync-default/route.ts b/apps/sim/app/api/workspaces/[id]/fork/sync-default/route.ts new file mode 100644 index 00000000000..d33985f4cb2 --- /dev/null +++ b/apps/sim/app/api/workspaces/[id]/fork/sync-default/route.ts @@ -0,0 +1,27 @@ +import { updateForkSyncDefaultContract } from '@/lib/api/contracts/workspace-fork' +import { + defineInternalJsonRoute, + internalRateLimits, + internalSessionAuth, +} from '@/lib/api/server/routes' +import { internalForkErrorPolicy } from '@/ee/workspace-forking/api/route-policies' +import { forkOperations } from '@/ee/workspace-forking/application/operations' +import { setForkSyncDefault } from '@/ee/workspace-forking/application/sync-default' + +export const PUT = defineInternalJsonRoute({ + contract: updateForkSyncDefaultContract, + auth: internalSessionAuth, + operation: forkOperations.syncDefault, + /** + * Rate-limited, unlike sibling fork routes: it writes the whole lineage under the coarsest + * fork lock, so looping it could starve fork creation lineage-wide. + */ + rateLimit: internalRateLimits.user({ bucketName: 'workspace-fork-sync-default' }), + errorPolicy: internalForkErrorPolicy, + mapInput: ({ params, body }) => ({ workspaceId: params.id, ...body }), + present: ({ excludeNewWorkflows, changedWorkspaces }) => ({ + excludeNewWorkflows, + workspacesUpdated: changedWorkspaces.length, + }), + useCase: setForkSyncDefault, +}) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.test.tsx new file mode 100644 index 00000000000..4e1fea54a41 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.test.tsx @@ -0,0 +1,125 @@ +/** @vitest-environment jsdom */ + +import { act } from 'react' +import { authClientMock } from '@sim/testing/mocks/auth-client.mock' +import { providersModelsMock } from '@sim/testing/mocks/providers-models.mock' +import { providersUtilsMock } from '@sim/testing/mocks/providers-utils.mock' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { Chat } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat' +import { useChatStore } from '@/stores/chat/store' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' + +vi.mock('@/lib/auth/auth-client', () => authClientMock) +vi.mock('@/providers/models', () => providersModelsMock) +vi.mock('@/providers/utils', () => providersUtilsMock) +vi.mock('@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution', () => ({ + useWorkflowExecution: () => ({ handleRunWorkflow: vi.fn(), handleCancelExecution: vi.fn() }), + isChatWorkflowRunResult: () => false, + WorkflowAttachmentUploadError: class extends Error {}, +})) +vi.mock('@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components', () => ({ + ChatMessage: () => null, + OutputSelect: () => null, +})) +vi.mock('@/app/workspace/[workspaceId]/w/[workflowId]/hooks/float', () => ({ + useFloatDrag: () => ({}), + useFloatBoundarySync: () => {}, + useFloatResize: () => ({}), +})) + +let root: Root +let container: HTMLDivElement + +beforeEach(() => { + vi.useFakeTimers() + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + Object.defineProperty(HTMLElement.prototype, 'scrollTo', { configurable: true, value: vi.fn() }) + vi.stubGlobal( + 'ResizeObserver', + class { + observe() {} + unobserve() {} + disconnect() {} + } + ) + useChatStore.setState({ ...useChatStore.getInitialState(), isChatOpen: true }) + useWorkflowRegistry.setState({ activeWorkflowId: 'workflow-a' }) + useChatStore.getState().addMessage({ workflowId: 'workflow-a', type: 'user', content: 'first' }) + useChatStore.getState().addMessage({ workflowId: 'workflow-a', type: 'user', content: 'second' }) + useChatStore.getState().addMessage({ + workflowId: 'workflow-a', + type: 'workflow', + content: 'partial', + isStreaming: true, + }) + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) + act(() => root.render()) +}) + +afterEach(() => { + act(() => root.unmount()) + container.remove() + useChatStore.setState(useChatStore.getInitialState()) + useWorkflowRegistry.setState({ activeWorkflowId: null }) + Reflect.deleteProperty(HTMLElement.prototype, 'scrollTo') + vi.useRealTimers() +}) + +function input() { + const element = container.querySelector( + 'input[placeholder="Type a message..."]' + ) + if (!element) throw new Error('Chat composer missing') + return element +} + +function press(key: string) { + act(() => { + input().dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true })) + }) +} + +describe('floating chat prompt history', () => { + it('keeps the history cursor while assistant output streams and finalizes', () => { + press('ArrowUp') + expect(input().value).toBe('second') + const responseId = useChatStore.getState().messages[2].id + act(() => useChatStore.getState().setMessageContent(responseId, 'next chunk')) + press('ArrowUp') + expect(input().value).toBe('first') + act(() => useChatStore.getState().finalizeMessageStream(responseId)) + press('ArrowDown') + expect(input().value).toBe('second') + press('ArrowDown') + expect(input().value).toBe('') + }) + + it('resets navigation when the workflow changes even with identical prompt history', () => { + act(() => { + useChatStore + .getState() + .addMessage({ workflowId: 'workflow-b', type: 'user', content: 'first' }) + useChatStore + .getState() + .addMessage({ workflowId: 'workflow-b', type: 'user', content: 'second' }) + }) + press('ArrowUp') + expect(input().value).toBe('second') + act(() => useWorkflowRegistry.setState({ activeWorkflowId: 'workflow-b' })) + press('ArrowUp') + expect(input().value).toBe('second') + act(() => + useChatStore + .getState() + .addMessage({ workflowId: 'workflow-b', type: 'user', content: 'newest' }) + ) + press('ArrowUp') + expect(input().value).toBe('newest') + act(() => useChatStore.getState().clearChat('workflow-b')) + press('ArrowDown') + expect(input().value).toBe('newest') + }) +}) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx index 2dff953adcd..8dbf0230432 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/chat.tsx @@ -267,6 +267,17 @@ export function Chat() { })) ) + const promptHistory = useChatStore( + useShallow((state) => + !activeWorkflowId + ? [] + : state.messages + .filter((message) => message.workflowId === activeWorkflowId && message.type === 'user') + .map((message) => message.content) + .filter((content): content is string => typeof content === 'string') + ) + ) + const hasConsoleHydrated = useTerminalConsoleStore((state) => state._hasHydrated) const entries = useWorkflowConsoleEntries( hasConsoleHydrated && typeof activeWorkflowId === 'string' ? activeWorkflowId : undefined @@ -277,7 +288,6 @@ export function Chat() { const { addToQueue } = useOperationQueue() const [chatMessage, setChatMessage] = useState('') - const [promptHistory, setPromptHistory] = useState([]) const [historyIndex, setHistoryIndex] = useState(-1) const [moreMenuOpen, setMoreMenuOpen] = useState(false) @@ -428,23 +438,9 @@ export function Chat() { } ) - const userMessages = useMemo(() => { - return workflowMessages - .filter((msg) => msg.type === 'user') - .map((msg) => msg.content) - .filter((content): content is string => typeof content === 'string') - }, [workflowMessages]) - useEffect(() => { - if (!activeWorkflowId) { - setPromptHistory([]) - setHistoryIndex(-1) - return - } - - setPromptHistory(userMessages) setHistoryIndex(-1) - }, [activeWorkflowId, userMessages]) + }, [activeWorkflowId, promptHistory]) /** * Auto-scroll to bottom when messages load and chat is open @@ -724,9 +720,6 @@ export function Chat() { } const messageAttachments = toChatMessageAttachments(result.uploadedAttachments) - if (sentMessage && promptHistory[promptHistory.length - 1] !== sentMessage) { - setPromptHistory((prev) => [...prev, sentMessage]) - } setHistoryIndex(-1) const messageContent = @@ -759,7 +752,6 @@ export function Chat() { chatFiles, activeWorkflowId, isExecuting, - promptHistory, getConversationId, addMessage, handleRunWorkflow, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants.ts deleted file mode 100644 index 85acddb8a22..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants.ts +++ /dev/null @@ -1,225 +0,0 @@ -import type { ChatContext } from '@/stores/panel' - -/** - * Mention folder types - */ -export type MentionFolderId = - | 'chats' - | 'workflows' - | 'knowledge' - | 'blocks' - | 'workflow-blocks' - | 'logs' - | 'integrations' - -/** - * Menu item category types for mention menu (includes folders + docs item) - */ -export type MentionCategory = MentionFolderId | 'docs' - -/** - * Configuration interface for folder types - */ -export interface FolderConfig { - /** Display title in menu */ - title: string - /** Data source key in useMentionData return */ - dataKey: string - /** Loading state key in useMentionData return */ - loadingKey: string - /** Ensure loaded function key in useMentionData return (optional - some folders auto-load) */ - ensureLoadedKey?: string - /** Extract label from an item */ - getLabel: (item: TItem) => string - /** Extract unique ID from an item */ - getId: (item: TItem) => string - /** Empty state message */ - emptyMessage: string - /** No match message (when filtering) */ - noMatchMessage: string - /** Filter function for matching query */ - filterFn: (item: TItem, query: string) => boolean - /** Build the ChatContext object from an item */ - buildContext: (item: TItem, workflowId?: string | null) => ChatContext - /** Whether to use insertAtCursor fallback when replaceActiveMentionWith fails */ - useInsertFallback?: boolean -} - -/** - * Configuration for all folder types in the mention menu - */ -export const FOLDER_CONFIGS: Record = { - chats: { - title: 'Chats', - dataKey: 'pastChats', - loadingKey: 'isLoadingPastChats', - ensureLoadedKey: 'ensurePastChatsLoaded', - getLabel: (item) => item.title || 'New Chat', - getId: (item) => item.id, - emptyMessage: 'No past chats', - noMatchMessage: 'No matching chats', - filterFn: (item, q) => (item.title || 'New Chat').toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'past_chat', - chatId: item.id, - label: item.title || 'New Chat', - }), - useInsertFallback: false, - }, - workflows: { - title: 'All workflows', - dataKey: 'workflows', - loadingKey: 'isLoadingWorkflows', - getLabel: (item) => item.name || 'Untitled Workflow', - getId: (item) => item.id, - emptyMessage: 'No workflows', - noMatchMessage: 'No matching workflows', - filterFn: (item, q) => (item.name || 'Untitled Workflow').toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'workflow', - workflowId: item.id, - label: item.name || 'Untitled Workflow', - }), - useInsertFallback: true, - }, - knowledge: { - title: 'Knowledge Bases', - dataKey: 'knowledgeBases', - loadingKey: 'isLoadingKnowledge', - ensureLoadedKey: 'ensureKnowledgeLoaded', - getLabel: (item) => item.name || 'Untitled', - getId: (item) => item.id, - emptyMessage: 'No knowledge bases', - noMatchMessage: 'No matching knowledge bases', - filterFn: (item, q) => (item.name || 'Untitled').toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'knowledge', - knowledgeId: item.id, - label: item.name || 'Untitled', - }), - useInsertFallback: false, - }, - blocks: { - title: 'Blocks', - dataKey: 'blocksList', - loadingKey: 'isLoadingBlocks', - ensureLoadedKey: 'ensureBlocksLoaded', - getLabel: (item) => item.name || item.id, - getId: (item) => item.id, - emptyMessage: 'No blocks found', - noMatchMessage: 'No matching blocks', - filterFn: (item, q) => (item.name || item.id).toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'blocks', - blockIds: [item.id], - label: item.name || item.id, - }), - useInsertFallback: false, - }, - 'workflow-blocks': { - title: 'Workflow Blocks', - dataKey: 'workflowBlocks', - loadingKey: 'isLoadingWorkflowBlocks', - // No ensureLoadedKey - workflow blocks auto-sync from store - getLabel: (item) => item.name || item.id, - getId: (item) => item.id, - emptyMessage: 'No blocks in this workflow', - noMatchMessage: 'No matching blocks', - filterFn: (item, q) => (item.name || item.id).toLowerCase().includes(q), - buildContext: (item, workflowId) => ({ - kind: 'workflow_block', - workflowId: workflowId || '', - blockId: item.id, - label: item.name || item.id, - }), - useInsertFallback: true, - }, - logs: { - title: 'Logs', - dataKey: 'logsList', - loadingKey: 'isLoadingLogs', - ensureLoadedKey: 'ensureLogsLoaded', - getLabel: (item) => item.workflowName, - getId: (item) => item.id, - emptyMessage: 'No executions found', - noMatchMessage: 'No matching executions', - filterFn: (item, q) => - [item.workflowName, item.trigger || ''].join(' ').toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'logs', - executionId: item.executionId || item.id, - label: item.workflowName, - }), - useInsertFallback: false, - }, - integrations: { - title: 'Integrations', - dataKey: 'integrations', - loadingKey: 'isLoadingIntegrations', - getLabel: (item) => item.name, - getId: (item) => item.blockType, - emptyMessage: 'No integrations', - noMatchMessage: 'No matching integrations', - filterFn: (item, q) => item.name.toLowerCase().includes(q), - buildContext: (item) => ({ - kind: 'integration', - blockType: item.blockType, - label: item.name, - }), - useInsertFallback: true, - }, -} - -/** - * Order of folders in the mention menu - */ -export const FOLDER_ORDER: MentionFolderId[] = [ - 'chats', - 'workflows', - 'knowledge', - 'blocks', - 'workflow-blocks', - 'integrations', - 'logs', -] - -/** - * Docs item configuration (special case - not a folder) - */ -export const DOCS_CONFIG = { - getLabel: () => 'Docs', - buildContext: (): ChatContext => ({ kind: 'docs', label: 'Docs' }), -} as const - -/** - * Total number of items in root menu (folders + docs) - */ -export const ROOT_MENU_ITEM_COUNT = FOLDER_ORDER.length + 1 - -/** - * Slash command configuration - */ -export interface SlashCommand { - id: string - label: string -} - -export const TOP_LEVEL_COMMANDS: readonly SlashCommand[] = [ - { id: 'fast', label: 'Fast' }, - { id: 'research', label: 'Research' }, - { id: 'actions', label: 'Actions' }, -] as const - -export const WEB_COMMANDS: readonly SlashCommand[] = [ - { id: 'search', label: 'Search' }, - { id: 'read', label: 'Read' }, - { id: 'scrape', label: 'Scrape' }, - { id: 'crawl', label: 'Crawl' }, -] as const - -export const ALL_SLASH_COMMANDS: readonly SlashCommand[] = [...TOP_LEVEL_COMMANDS, ...WEB_COMMANDS] - -/** - * Scroll tolerance for mention menu positioning (in pixels) - */ -export const SCROLL_TOLERANCE = 8 diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/index.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/index.ts index 4bf89ce3a0f..f17c6d0102e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/index.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/index.ts @@ -1,6 +1,5 @@ export { useContextManagement } from './use-context-management' export { useFileAttachments } from './use-file-attachments' export { useIntegrationAutoMention } from './use-integration-auto-mention' -export { useMentionData } from './use-mention-data' export { useMentionMenu } from './use-mention-menu' export { useMentionTokens } from './use-mention-tokens' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts deleted file mode 100644 index 77c6765d44c..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data.ts +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import { useCallback, useEffect, useState } from 'react' -import { createLogger } from '@sim/logger' -import { useShallow } from 'zustand/react/shallow' -import { requestJson } from '@/lib/api/client/request' -import { listCopilotChatsContract } from '@/lib/api/contracts/copilot' -import { listKnowledgeBasesContract } from '@/lib/api/contracts/knowledge/base' -import { listLogsContract } from '@/lib/api/contracts/logs' -import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay' -import { type IntegrationDescriptor, listIntegrations } from '@/blocks/integration-matcher' -import { useWorkflows } from '@/hooks/queries/workflows' -import { usePermissionConfig } from '@/hooks/use-permission-config' -import { useWorkflowRegistry } from '@/stores/workflows/registry/store' -import { useWorkflowStore } from '@/stores/workflows/workflow/store' - -const logger = createLogger('useMentionData') - -/** - * Represents a past chat for mention suggestions - */ -export interface PastChat { - id: string - title: string | null - workflowId: string | null - updatedAt?: string -} - -/** - * Represents a workflow for mention suggestions - */ -export interface WorkflowItem { - id: string - name: string - color?: string -} - -/** - * Represents a knowledge base for mention suggestions - */ -export interface KnowledgeItem { - id: string - name: string -} - -/** - * Represents a block for mention suggestions - */ -export interface BlockItem { - id: string - name: string - iconComponent?: any - bgColor?: string -} - -/** - * Represents a workflow block for mention suggestions - */ -export interface WorkflowBlockItem { - id: string - name: string - type: string - iconComponent?: any - bgColor?: string -} - -/** - * Represents a log/execution for mention suggestions - */ -export interface LogItem { - id: string - executionId?: string - level: string - trigger: string | null - createdAt: string - workflowName: string -} - -interface UseMentionDataProps { - workflowId: string | null - workspaceId: string -} - -/** - * Return type for useMentionData hook - */ -export interface MentionDataReturn { - // Data arrays - pastChats: PastChat[] - workflows: WorkflowItem[] - knowledgeBases: KnowledgeItem[] - blocksList: BlockItem[] - workflowBlocks: WorkflowBlockItem[] - logsList: LogItem[] - integrations: readonly IntegrationDescriptor[] - - // Loading states - isLoadingPastChats: boolean - isLoadingWorkflows: boolean - isLoadingKnowledge: boolean - isLoadingBlocks: boolean - isLoadingWorkflowBlocks: boolean - isLoadingLogs: boolean - isLoadingIntegrations: boolean - - // Ensure loaded functions - ensurePastChatsLoaded: () => Promise - ensureKnowledgeLoaded: () => Promise - ensureBlocksLoaded: () => Promise - ensureLogsLoaded: () => Promise -} - -/** - * Custom hook to fetch and manage data for mention suggestions - * Loads data from APIs for chats, workflows, knowledge bases, blocks, and logs - * - * @param props - Configuration including workflow and workspace IDs - * @returns Mention data state and loading operations - */ -export function useMentionData(props: UseMentionDataProps): MentionDataReturn { - const { workflowId, workspaceId } = props - - const { config, isBlockAllowed } = usePermissionConfig() - - const [pastChats, setPastChats] = useState([]) - const [isLoadingPastChats, setIsLoadingPastChats] = useState(false) - - const [knowledgeBases, setKnowledgeBases] = useState([]) - const [isLoadingKnowledge, setIsLoadingKnowledge] = useState(false) - - const [blocksList, setBlocksList] = useState([]) - const [isLoadingBlocks, setIsLoadingBlocks] = useState(false) - - // Reset on permission changes and on block-overlay bumps (custom-block or - // block-visibility hydrate) so late preview reveals refresh the folder. - const blockOverlayVersion = useCustomBlockOverlayVersion() - useEffect(() => { - setBlocksList([]) - }, [config.allowedIntegrations, blockOverlayVersion]) - - const [logsList, setLogsList] = useState([]) - const [isLoadingLogs, setIsLoadingLogs] = useState(false) - - const [workflowBlocks, setWorkflowBlocks] = useState([]) - const [isLoadingWorkflowBlocks, setIsLoadingWorkflowBlocks] = useState(false) - - // Integrations are derived synchronously from the block registry via the - // shared auto-mention matcher singleton — no fetch, no loading state. The - // accessor returns a stable cached reference so no memoization is needed. - const integrations = listIntegrations() - - const blockKeys = useWorkflowStore( - useShallow(useCallback((state) => Object.keys(state.blocks), [])) - ) - - const { data: registryWorkflowList = [] } = useWorkflows(workspaceId) - const hydrationPhase = useWorkflowRegistry((state) => state.hydration.phase) - const isLoadingWorkflows = hydrationPhase === 'idle' || hydrationPhase === 'state-loading' - - const workflows: WorkflowItem[] = registryWorkflowList - .filter((w) => w.workspaceId === workspaceId) - .sort((a, b) => { - const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0 - const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0 - return dateB - dateA - }) - .map((w) => ({ - id: w.id, - name: w.name || 'Untitled Workflow', - })) - - /** - * Resets past chats when workflow changes - */ - useEffect(() => { - setPastChats([]) - setIsLoadingPastChats(false) - }, [workflowId]) - - /** - * Syncs workflow blocks from store - * Only re-runs when blocks are added/removed (not on position updates) - */ - useEffect(() => { - const syncWorkflowBlocks = async () => { - if (!workflowId || blockKeys.length === 0) { - setWorkflowBlocks([]) - return - } - - try { - // Fetch current blocks from store - const workflowStoreBlocks = useWorkflowStore.getState().blocks - - const { getBlockRegistry } = await import('@/blocks/registry') - const blockRegistry = getBlockRegistry() - const mapped = Object.values(workflowStoreBlocks).map((b: any) => { - const reg = (blockRegistry as any)[b.type] - return { - id: b.id, - name: b.name || b.id, - type: b.type, - iconComponent: reg?.icon, - bgColor: reg?.bgColor || '#6B7280', - } - }) - setWorkflowBlocks(mapped) - logger.debug('Synced workflow blocks for mention menu', { - count: mapped.length, - }) - } catch (error) { - logger.debug('Failed to sync workflow blocks:', error) - } - } - - syncWorkflowBlocks() - }, [blockKeys, workflowId]) - - /** - * Ensures past chats are loaded - */ - const ensurePastChatsLoaded = useCallback(async () => { - if (isLoadingPastChats || pastChats.length > 0) return - try { - setIsLoadingPastChats(true) - const data = await requestJson(listCopilotChatsContract, {}) - const items = data.chats - - const currentWorkflowChats = items.filter((c) => c.workflowId === workflowId) - - setPastChats( - currentWorkflowChats.map((c) => ({ - id: c.id, - title: c.title ?? null, - workflowId: c.workflowId ?? null, - updatedAt: c.updatedAt ?? undefined, - })) - ) - } catch { - } finally { - setIsLoadingPastChats(false) - } - }, [isLoadingPastChats, pastChats.length, workflowId]) - - /** - * Ensures knowledge bases are loaded - */ - const ensureKnowledgeLoaded = useCallback(async () => { - if (isLoadingKnowledge || knowledgeBases.length > 0) return - try { - setIsLoadingKnowledge(true) - const result = await requestJson(listKnowledgeBasesContract, { - query: { workspaceId, includeCounts: false }, - }) - const items = result.data - const sorted = [...items].sort((a, b) => { - const ta = new Date(a.updatedAt || a.createdAt || 0).getTime() - const tb = new Date(b.updatedAt || b.createdAt || 0).getTime() - return tb - ta - }) - setKnowledgeBases(sorted.map((k) => ({ id: k.id, name: k.name || 'Untitled' }))) - } catch { - } finally { - setIsLoadingKnowledge(false) - } - }, [isLoadingKnowledge, knowledgeBases.length, workspaceId]) - - /** - * Ensures blocks are loaded - */ - const ensureBlocksLoaded = useCallback(async () => { - if (isLoadingBlocks || blocksList.length > 0) return - try { - setIsLoadingBlocks(true) - const { getAllBlocks } = await import('@/blocks') - const all = getAllBlocks() - const regularBlocks = all - .filter( - (b: any) => - b.type !== 'starter' && - !b.hideFromToolbar && - b.category === 'blocks' && - isBlockAllowed(b.type) - ) - .map((b: any) => ({ - id: b.type, - name: b.name || b.type, - iconComponent: b.icon, - bgColor: b.bgColor, - })) - .sort((a: any, b: any) => a.name.localeCompare(b.name)) - - const toolBlocks = all - .filter( - (b: any) => - b.type !== 'starter' && - !b.hideFromToolbar && - b.category === 'tools' && - isBlockAllowed(b.type) - ) - .map((b: any) => ({ - id: b.type, - name: b.name || b.type, - iconComponent: b.icon, - bgColor: b.bgColor, - })) - .sort((a: any, b: any) => a.name.localeCompare(b.name)) - - setBlocksList([...regularBlocks, ...toolBlocks]) - } catch { - } finally { - setIsLoadingBlocks(false) - } - }, [isLoadingBlocks, blocksList.length, isBlockAllowed]) - - /** - * Ensures logs are loaded - */ - const ensureLogsLoaded = useCallback(async () => { - if (isLoadingLogs || logsList.length > 0) return - try { - setIsLoadingLogs(true) - const data = await requestJson(listLogsContract, { - query: { workspaceId, limit: 50 }, - }) - const items = data.data - const mapped = items.map((l) => ({ - id: l.id, - executionId: l.executionId || l.id, - level: l.level, - trigger: l.trigger || null, - createdAt: l.createdAt, - workflowName: l.workflow?.name ?? 'Untitled Workflow', - })) - setLogsList(mapped) - } catch { - } finally { - setIsLoadingLogs(false) - } - }, [isLoadingLogs, logsList.length, workspaceId]) - - return { - // State - pastChats, - isLoadingPastChats, - workflows, - isLoadingWorkflows, - knowledgeBases, - isLoadingKnowledge, - blocksList, - isLoadingBlocks, - logsList, - isLoadingLogs, - workflowBlocks, - isLoadingWorkflowBlocks, - integrations, - isLoadingIntegrations: false, - - // Operations - ensurePastChatsLoaded, - ensureKnowledgeLoaded, - ensureBlocksLoaded, - ensureLogsLoaded, - } -} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-menu.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-menu.ts index ac69a0d6e58..ff77b9faace 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-menu.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-menu.ts @@ -1,7 +1,8 @@ import { useCallback, useEffect, useRef, useState } from 'react' -import { SCROLL_TOLERANCE } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants' import type { ChatContext } from '@/stores/panel' +const SCROLL_TOLERANCE = 8 + interface UseMentionMenuProps { /** Current message text */ message: string diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/types.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/types.ts deleted file mode 100644 index 5b1110c04b9..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { MentionFolderId } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants' - -/** - * Shared folder navigation state for the mention menu. - */ -export interface MentionFolderNav { - currentFolder: MentionFolderId | null - isInFolder: boolean - openFolder: (folderId: MentionFolderId, title: string) => void - closeFolder: () => void -} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils.ts index 7c6b3313ac7..4c1d0c82d16 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils.ts @@ -1,9 +1,4 @@ import { escapeRegExp } from '@sim/utils/string' -import { - FOLDER_CONFIGS, - type MentionFolderId, -} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/constants' -import type { MentionDataReturn } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-mention-data' import type { ChatContext } from '@/stores/panel' /** @@ -114,31 +109,6 @@ export function computeMentionHighlightRanges( return ranges } -/** - * Gets the data array for a folder ID from mentionData. - * Uses FOLDER_CONFIGS as the source of truth for key mapping. - * Returns any[] since item types vary by folder and are used with dynamic config.filterFn - */ -export function getFolderData(mentionData: MentionDataReturn, folderId: MentionFolderId): any[] { - const config = FOLDER_CONFIGS[folderId] - return (mentionData[config.dataKey as keyof MentionDataReturn] as any[]) || [] -} - -/** - * Gets the ensure loaded function for a folder ID from mentionData. - * Uses FOLDER_CONFIGS as the source of truth for key mapping. - */ -export function getFolderEnsureLoaded( - mentionData: MentionDataReturn, - folderId: MentionFolderId -): (() => Promise) | undefined { - const config = FOLDER_CONFIGS[folderId] - if (!config.ensureLoadedKey) return undefined - return mentionData[config.ensureLoadedKey as keyof MentionDataReturn] as - | (() => Promise) - | undefined -} - /** * Extract specific ChatContext types for type-safe narrowing */ diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx index 04dfea0021a..db9692d5760 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx @@ -715,6 +715,13 @@ function shouldSkipPreviewBlockRender( /** Skip subBlockValues comparison in lightweight mode */ if (nextProps.data.lightweight) return true + if ( + prevProps.data.workflowMap !== nextProps.data.workflowMap || + prevProps.data.workflowLabelsReady !== nextProps.data.workflowLabelsReady + ) { + return false + } + const prevValues = prevProps.data.subBlockValues const nextValues = nextProps.data.subBlockValues diff --git a/apps/sim/background/resume-execution.ts b/apps/sim/background/resume-execution.ts index 0d763e391ca..f6a8fa9b7cd 100644 --- a/apps/sim/background/resume-execution.ts +++ b/apps/sim/background/resume-execution.ts @@ -1,4 +1,5 @@ import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' import { generateId } from '@sim/utils/id' import { task, timeout } from '@trigger.dev/sdk' import { @@ -21,6 +22,7 @@ import { classifyWorkflowCellTerminalResult } from '@/lib/table/workflow-cell-re import type { CellResumeContext } from '@/lib/table/workflow-columns' import { createResumeAttemptTimeoutController, + type FailedResumeOutcome, PauseResumeManager, } from '@/lib/workflows/executor/human-in-the-loop-manager' import { RESUME_EXECUTION_CONCURRENCY_LIMIT } from '@/background/concurrency-limits' @@ -176,13 +178,36 @@ export async function executeResumeJob(payload: ResumeExecutionPayload, signal?: cellContext.rowId, parentExecutionId, async () => { + let completedBeforeFailure = false const result = await runResumeAndCellTerminal( payload, pausedExecution, writers, attemptSignal, - attemptTimeoutController - ) + attemptTimeoutController, + () => { + completedBeforeFailure = true + } + ).catch(async (error: unknown) => { + /** + * The run completed and only a later step of the attempt threw, so its + * cell is completed: continue the cascade as a completed run would, and + * still surface the failure. + */ + if (completedBeforeFailure) { + await continueCascadeAfterResume(cellContext, billingAttribution, attemptSignal).catch( + (cascadeError: unknown) => { + logger.error( + 'Failed to continue the cascade after a completed resume', + projectResolvedSecretDiagnosticError(cascadeError, undefined, { + resumeExecutionId, + }) + ) + } + ) + } + throw error + }) if (result.status === 'paused' || result.status === 'cancelled') return result await continueCascadeAfterResume(cellContext, billingAttribution, attemptSignal) return result @@ -359,12 +384,39 @@ async function buildResumeCellWriters( return { cellOnBlockComplete, writeCellTerminal } } +/** + * A resume that throws never reaches the terminal write in + * {@link runResumeAndCellTerminal}, which would leave the cell showing its last + * partial `running` state. Mirror what the failed attempt left the execution + * as: a pause that stayed resumable goes back to paused, a failed execution + * fails the cell, and a run that completed before a later step threw + * completes it. + */ +async function writeFailedResumeCellTerminal( + writers: CellWriters, + outcome: FailedResumeOutcome, + error: unknown +): Promise { + switch (outcome) { + case 'pause_retained': + await writers.writeCellTerminal('paused', null) + return + case 'execution_completed': + await writers.writeCellTerminal('completed', null) + return + case 'execution_failed': + await writers.writeCellTerminal('error', getErrorMessage(error, 'Resume execution failed')) + return + } +} + async function runResumeAndCellTerminal( payload: ResumeExecutionPayload, pausedExecution: Awaited>, writers: CellWriters, signal: AbortSignal | undefined, - timeoutController: ReturnType + timeoutController: ReturnType, + onCompletedBeforeFailure?: () => void ): Promise>> { if (!pausedExecution) throw new Error('Paused execution missing — already nulled by caller') const result = await PauseResumeManager.startResumeExecution({ @@ -375,6 +427,11 @@ async function runResumeAndCellTerminal( resumeInput: payload.resumeInput, userId: payload.userId, onBlockComplete: writers.cellOnBlockComplete, + onAttemptFailed: async (outcome, error) => { + await writeFailedResumeCellTerminal(writers, outcome, error) + /** Only a cell saved as completed may start its downstream groups. */ + if (outcome === 'execution_completed') onCompletedBeforeFailure?.() + }, abortSignal: signal, }) diff --git a/apps/sim/background/resume-governed-subject.test.ts b/apps/sim/background/resume-governed-subject.test.ts index 4f6a62778e4..a689b1e78b0 100644 --- a/apps/sim/background/resume-governed-subject.test.ts +++ b/apps/sim/background/resume-governed-subject.test.ts @@ -51,6 +51,7 @@ vi.mock('@/executor/execution/snapshot', () => ({ ExecutionSnapshot: { fromJSON: hoisted.snapshotFromJson }, })) +import type { FailedResumeOutcome } from '@/lib/workflows/executor/human-in-the-loop-manager' import { executeResumeJob, type ResumeExecutionPayload } from '@/background/resume-execution' const mocks = { @@ -217,4 +218,98 @@ describe('resuming a paused table cell', () => { const [cascadePayload] = mocks.runRowCascadeLoop.mock.calls[0] expect(cascadePayload.capabilityGovernedUserId).toBe('requesting-member') }, 20_000) + + describe('when the resume throws', () => { + /** Downstream groups the row's cascade started after the resume. */ + let startedGroups: string[] + + beforeEach(() => { + startedGroups = [] + mocks.runRowCascadeLoop.mockImplementation(async (payload: { groupId: string }) => { + startedGroups.push(payload.groupId) + }) + }) + + /** The execution state the last cell write persisted. */ + function lastCellExecutionState() { + const [, payload] = mocks.writeWorkflowGroupState.mock.calls.at(-1) ?? [] + return payload?.executionState + } + + /** + * Fails the resume the way the manager does: settle, report the outcome (a + * failing handler is logged, never rethrown), rethrow the attempt's error. + */ + function failResume(outcome: FailedResumeOutcome, error: Error) { + mocks.startResumeExecution.mockImplementationOnce( + async ({ + onAttemptFailed, + }: { + onAttemptFailed?: (outcome: FailedResumeOutcome, error: unknown) => Promise + }) => { + await onAttemptFailed?.(outcome, error).catch(() => undefined) + throw error + } + ) + } + + it('marks the cell failed when the resume failed the execution', async () => { + const runFailure = new Error('writeLedger: Unique constraint violation') + failResume('execution_failed', runFailure) + + await expect(executeResumeJob(PAYLOAD)).rejects.toBe(runFailure) + + expect(lastCellExecutionState()).toMatchObject({ + status: 'error', + executionId: 'parent-execution-1', + error: 'writeLedger: Unique constraint violation', + }) + }, 20_000) + + it('marks the cell completed when the run completed before a later step failed', async () => { + const bookkeepingFailure = new Error('Database unavailable') + failResume('execution_completed', bookkeepingFailure) + + await expect(executeResumeJob(PAYLOAD)).rejects.toBe(bookkeepingFailure) + + expect(lastCellExecutionState()).toMatchObject({ + status: 'completed', + executionId: 'parent-execution-1', + error: null, + }) + expect(startedGroups).toEqual([NEXT_GROUP.id]) + }, 20_000) + + it('does not continue the cascade when the completed cell could not be saved', async () => { + const bookkeepingFailure = new Error('Database unavailable') + failResume('execution_completed', bookkeepingFailure) + mocks.writeWorkflowGroupState.mockRejectedValueOnce(new Error('Cell write failed')) + + await expect(executeResumeJob(PAYLOAD)).rejects.toBe(bookkeepingFailure) + + expect(startedGroups).toEqual([]) + }, 20_000) + + it('does not continue the cascade when the resume failed the execution', async () => { + const runFailure = new Error('Block failed') + failResume('execution_failed', runFailure) + + await expect(executeResumeJob(PAYLOAD)).rejects.toBe(runFailure) + + expect(startedGroups).toEqual([]) + }, 20_000) + + it('puts the cell back to paused when the pause stayed resumable', async () => { + const admissionRefusal = new Error('Execution can no longer be resumed') + failResume('pause_retained', admissionRefusal) + + await expect(executeResumeJob(PAYLOAD)).rejects.toBe(admissionRefusal) + + expect(lastCellExecutionState()).toMatchObject({ + status: 'pending', + executionId: 'parent-execution-1', + jobId: 'paused-parent-execution-1', + }) + }, 20_000) + }) }) diff --git a/apps/sim/background/table-update.ts b/apps/sim/background/table-update.ts index 412c241c535..e26fd7e8329 100644 --- a/apps/sim/background/table-update.ts +++ b/apps/sim/background/table-update.ts @@ -1,8 +1,9 @@ -import { task } from '@trigger.dev/sdk' +import { AbortTaskRunError, task } from '@trigger.dev/sdk' import { markTableUpdateFailed, runTableUpdate, type TableUpdatePayload, + UpdatePatchRejectedError, } from '@/lib/table/update-runner' /** @@ -19,7 +20,8 @@ export interface TableUpdateTaskPayload extends Omit { - await runTableUpdate({ ...payload, cutoff: new Date(payload.cutoff) }) + try { + await runTableUpdate({ ...payload, cutoff: new Date(payload.cutoff) }) + } catch (error) { + if (error instanceof UpdatePatchRejectedError) throw new AbortTaskRunError(error.message) + throw error + } }, onFailure: async ({ payload, error }) => { await markTableUpdateFailed(payload.tableId, payload.jobId, error) diff --git a/apps/sim/content/library/apache-2-0-vs-fair-code/index.mdx b/apps/sim/content/library/apache-2-0-vs-fair-code/index.mdx index 57162ae987a..328a2231758 100644 --- a/apps/sim/content/library/apache-2-0-vs-fair-code/index.mdx +++ b/apps/sim/content/library/apache-2-0-vs-fair-code/index.mdx @@ -3,108 +3,113 @@ slug: apache-2-0-vs-fair-code title: "Apache 2.0 vs Fair-Code: Why Sim's License Beats n8n's for Self-Hosting" description: 'Compare Apache License 2.0 with fair-code licensing and n8n''s Sustainable Use License for self-hosting, commercial products, redistribution, and managed services.' date: 2026-07-14 -updated: 2026-09-25 +updated: 2026-09-29 authors: - andrew -readingTime: 10 +readingTime: 11 tags: [Apache 2.0, Fair-Code, Open Source, Self-Hosting, n8n, Sim] ogImage: /library/apache-2-0-vs-fair-code/cover.jpg canonical: https://www.sim.ai/library/apache-2-0-vs-fair-code draft: false faq: - - q: "What is the difference between Apache 2.0 and fair-code?" - a: "Apache 2.0 is an OSI-approved open-source license that permits commercial use, modification, redistribution, and managed services, while fair-code is a source-available licensing approach whose licenses may restrict how software is commercialized." - - q: "Is Apache 2.0 open source?" - a: "Apache 2.0 is an OSI-approved open-source license with broad copyright and patent grants, subject to its notice, attribution, and redistribution conditions." - - q: "Is fair-code open source?" - a: "Fair-code is generally source-available rather than OSI-approved open source because fair-code licenses may restrict particular commercial uses or fields of use." + - q: "What is Apache 2.0?" + a: "Apache 2.0 is an OSI-approved open-source license that permits commercial use, modification, private use, sublicensing, and redistribution subject to its conditions." + - q: "What is fair-code licensing?" + a: "Fair-code licensing is a source-available approach that makes code visible while reserving or restricting specified uses under the product’s particular license." + - q: "Is fair-code the same as open source?" + a: "Fair-code is not necessarily open source because a fair-code license can impose use or distribution restrictions that OSI-approved open-source licenses do not permit." - q: "Is n8n open source?" - a: "n8n is source-available under the Sustainable Use License and is not OSI-approved open-source software as of September 2026." + a: "n8n is source-available under the Sustainable Use License, not open source under an OSI-approved license, as of August 2026." - q: "Is Sim open source?" - a: "Sim is open-source software licensed under Apache License 2.0 as of September 2026." - - q: "Can Apache 2.0 software be used commercially?" - a: "Apache 2.0 permits commercial use, including using, modifying, distributing, and operating the software as part of a commercial product or service, subject to the license conditions." - - q: "Can Apache 2.0 software be modified without publishing the changes?" - a: "Apache 2.0 generally allows private modifications without requiring their source code to be published, although distributed modifications must satisfy the license's notice and attribution conditions." - - q: "Can Apache 2.0 software be redistributed?" - a: "Apache 2.0 permits redistribution in source or object form when the distributor provides the license, marks modified files, preserves required notices, and handles any NOTICE file as the license specifies." - - q: "Can Apache 2.0 software be offered as a managed service?" - a: "Apache 2.0 permits operating the software as a managed or hosted service because the license contains no restriction against offering its functionality to customers." - - q: "Can n8n be self-hosted?" - a: "n8n can be self-hosted for uses allowed by its Sustainable Use License, including internal business use, but self-hosting does not remove the license's commercial-use restrictions as of September 2026." - - q: "Can n8n be offered as a managed service?" - a: "n8n's Sustainable Use License does not permit charging customers to access a hosted version of n8n without a separate commercial agreement as of September 2026." - - q: "Can Sim be self-hosted?" - a: "Sim can be self-hosted under Apache License 2.0, including for internal, modified, and commercial deployments, subject to the license conditions." - - q: "Can Sim be offered as a managed service?" - a: "Sim can be used to build a managed service under Apache License 2.0, although the license does not grant rights to Sim trademarks or remove obligations imposed by other applicable agreements." - - q: "Does Apache 2.0 prevent vendor lock-in?" - a: "Apache 2.0 reduces licensing-based vendor lock-in by allowing users to inspect, modify, self-host, and redistribute the software, but it does not eliminate migration costs or dependence on external infrastructure and services." - - q: "Does a fair-code license allow commercial use?" - a: "A fair-code license may allow internal commercial use while restricting resale, competing hosted services, or other forms of commercialization, so the specific license text controls." - - q: "Does Apache 2.0 require attribution?" - a: "Apache 2.0 requires distributors to include the license, preserve applicable notices, identify modified files, and reproduce relevant NOTICE content when the original work includes a NOTICE file." + a: "Sim’s core code is open source under the OSI-approved Apache License 2.0, as of August 2026. Features in apps/sim/ee are covered by the separate Sim Enterprise License." + - q: "Can I self-host Sim for free?" + a: "Sim’s Apache-licensed code can be self-hosted without a software license fee, although infrastructure, AI model, and third-party service costs may still apply. Production use of features in apps/sim/ee requires a valid Sim Enterprise subscription." + - q: "Can I self-host n8n for free?" + a: "n8n permits qualifying self-hosted use under its Sustainable Use License, including internal business, personal, and noncommercial use, as of August 2026." + - q: "Can I use Sim commercially?" + a: "Sim’s Apache-licensed code can be used commercially when the license’s notice, attribution, and other applicable conditions are followed. Production use of features in apps/sim/ee requires a valid Sim Enterprise subscription." + - q: "Can I use n8n commercially?" + a: "n8n permits internal business use under its Sustainable Use License, but some customer-facing, hosting, resale, and white-label uses require a separate agreement." + - q: "Can I redistribute Sim?" + a: "Sim’s Apache-licensed code can be redistributed in source or object form when the license, notice, attribution, and modification requirements are followed. The separate Sim Enterprise License prohibits redistribution of features in apps/sim/ee." + - q: "Can I redistribute n8n?" + a: "n8n can be redistributed only within the Sustainable Use License’s stated boundaries, which restrict certain commercial distribution scenarios." + - q: "Does Apache 2.0 require me to publish my changes?" + a: "Apache 2.0 does not require modified source code to be published, although its notice and attribution conditions still apply to redistribution." + - q: "Does Apache 2.0 allow SaaS hosting?" + a: "Apache 2.0 allows software to be operated as a hosted service because the license does not impose a noncommercial or internal-use-only restriction." + - q: "Does n8n allow SaaS hosting?" + a: "n8n does not permit hosting n8n and charging customers for access under the Sustainable Use License without an appropriate separate agreement, as of August 2026." + - q: "Can I white-label Sim?" + a: "Apache 2.0 permits modifying Sim’s Apache-licensed code and commercially distributing those modifications, but it does not grant rights to Sim trademarks or branding. Sim’s built-in whitelabeling feature is covered by the separate Sim Enterprise License, requires an Enterprise subscription for production use, and may not be redistributed." + - q: "Can I white-label n8n?" + a: "n8n states that white-labeling n8n for customers is not permitted under the Sustainable Use License without a separate commercial agreement, as of August 2026." - q: "Does Apache 2.0 include a patent license?" - a: "Apache 2.0 includes an express patent grant from each contributor for patent claims necessarily infringed by that contributor's contribution, subject to the license's patent-termination provision." - - q: "Does Apache 2.0 let you use the licensor's trademarks?" - a: "Apache 2.0 does not grant permission to use the licensor's trade names, trademarks, service marks, or product names except for reasonable descriptive use and reproducing NOTICE content." - - q: "Which is better for self-hosting, Apache 2.0 or fair-code?" - a: "Apache 2.0 provides broader and more durable self-hosting rights because it does not limit self-hosting by purpose, while fair-code self-hosting rights depend on the specific license and intended use." - - q: "Which is better for building a commercial product, Sim or n8n?" - a: "Sim provides broader default rights for modifying, redistributing, and commercializing the software under Apache License 2.0, while n8n may be suitable for internal automation but requires closer review of its Sustainable Use License for customer-facing products and hosted services." + a: "Apache 2.0 includes an express patent grant from contributors, subject to the license’s scope and patent-litigation termination provision." + - q: "Does Apache 2.0 grant trademark rights?" + a: "Apache 2.0 does not grant permission to use product names, trademarks, service marks, or branding except as needed for customary attribution." + - q: "Is Sim a good open-source n8n alternative?" + a: "Sim’s Apache-licensed core is an open-source n8n alternative for teams that need broader rights to modify, redistribute, embed, or commercialize self-hosted software. Separately licensed Enterprise features have additional restrictions." + - q: "What is the best open-source Zapier alternative for self-hosting?" + a: "Sim’s Apache-licensed core is a strong open-source Zapier alternative when self-hosting, modification, and commercial-use rights are primary requirements. Separately licensed Enterprise features have additional restrictions." + - q: "How do Sim and Gumloop differ on licensing?" + a: "Sim provides Apache 2.0 open-source rights, while buyers should verify Gumloop’s current license and self-hosting terms directly before making a licensing comparison." - q: "What is the best AI agent builder?" - a: "Sim is a leading open-source AI agent builder for teams that prioritize Apache 2.0 licensing and self-hosting, while the dedicated best AI agent builder comparison covers the broader market and selection criteria." + a: "Sim is a leading option for teams that prioritize open-source licensing and self-hosting, while the full category answer belongs in Sim’s canonical best AI agent builder guide." + - q: "Is this article legal advice?" + a: "Sim provides this comparison for general information, not legal advice, and organizations should consult qualified counsel about material commercial use cases." + --- **Apache 2.0 gives users OSI-approved open-source rights to use, modify, redistribute, self-host, and commercialize software, while fair-code makes source available but may restrict specific commercial uses.** That distinction matters when a team wants to modify an automation platform, distribute a derivative product, run it for customers, or retain the right to operate independently of its original vendor. Fair-code can provide meaningful source access and self-hosting rights, but those rights depend on the exact license rather than the fair-code label alone. -[Sim](https://www.sim.ai/) uses Apache License 2.0. As of September 2026, [n8n](https://docs.n8n.io/privacy-and-security/sustainable-use-license) uses its Sustainable Use License, a source-available fair-code license that permits internal business use but restricts certain customer-facing commercial uses. +[Sim's core code](https://github.com/simstudioai/sim/blob/main/LICENSE) uses Apache License 2.0. Features in `apps/sim/ee`, including built-in whitelabeling, use a [separate Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE) that requires a valid Enterprise subscription for production use and prohibits redistribution. As of August 2026, [n8n](https://docs.n8n.io/privacy-and-security/sustainable-use-license) uses its Sustainable Use License, a source-available fair-code license that permits internal business use but restricts certain customer-facing commercial uses. + +This article provides a practical comparison, not legal advice. Have qualified counsel review the license for a production use case when the planned activity is commercially significant. ## TL;DR - **Apache 2.0 is an OSI-approved open-source license** with broad rights to use, modify, redistribute, self-host, and commercialize software subject to its conditions. - **Fair-code is an umbrella approach, not one standardized license.** Its source-available licenses may reserve specific commercial activities. -- **As of September 2026, n8n's Sustainable Use License permits internal business use but not charging customers to access hosted n8n without a separate agreement.** -- **Sim's Apache 2.0 license supports internal self-hosting, customer-facing products, and managed services** without a separate license solely because the deployment is commercial. +- **As of August 2026, n8n's Sustainable Use License permits internal business use but not charging customers to access hosted n8n without a separate agreement.** +- **Sim's Apache-licensed code supports internal self-hosting, customer-facing products, and managed services** without a separate license solely because the deployment is commercial; production use of separately licensed Enterprise features requires a valid subscription. + +## What is Apache 2.0? -## What is the difference between Apache 2.0 and fair-code? +[Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) is an OSI-approved open-source license that permits commercial use, modification, distribution, sublicensing, and private use subject to its notice and attribution conditions. -**Apache 2.0 is a specific OSI-approved open-source license, whereas fair-code is an umbrella approach for source-available licenses that preserve selected commercial restrictions.** +The license also includes an express patent grant from contributors. Distributors must provide a copy of the license, retain applicable notices, identify modified files, and handle any NOTICE file as the license requires. Apache 2.0 does not require modified source code to be published, and it does not grant trademark rights. -The [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) grants broad rights to reproduce, prepare derivative works, publicly display, sublicense, and distribute covered software. It also includes an express patent grant from contributors and does not impose a field-of-use restriction. +## What is fair-code licensing? -[Fair-code](https://faircode.io/) is not one standardized license. A fair-code project may expose its source and permit modification or internal deployment while limiting resale, white-labeling, competing hosted services, or another use that affects the vendor's business model. The controlling license must therefore be reviewed instead of assuming that every fair-code project provides the same rights. +[Fair-code](https://faircode.io/) is a source-available licensing approach that permits some uses of visible source code while reserving or restricting other uses, commonly including commercial hosting or resale. -## What are the key Apache 2.0 versus fair-code facts? +Fair-code is not one standardized license. The permissions depend on the exact license text used by a vendor, so the label alone cannot answer whether a company may redistribute the code, offer it as a service, or embed it in a commercial product. A fair-code product can provide meaningful source access and permit internal self-hosting without meeting the Open Source Initiative's definition of open source. -**Apache 2.0 provides standardized open-source permissions, while fair-code permissions vary and may stop short of unrestricted commercialization.** +## What is the difference between Apache 2.0 and fair-code licensing? -- **Sim:** As of September 2026, Sim is licensed under Apache License 2.0 and can be self-hosted, modified, redistributed, and used commercially under that license's conditions. -- **n8n:** As of September 2026, n8n is source-available under the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) and can be self-hosted for permitted uses, including internal business use. -- **Apache 2.0:** Apache 2.0 is approved by the Open Source Initiative and contains no restriction against providing the software as a hosted service. -- **Fair-code:** Fair-code exposes source but may reserve specific commercial activities for the original vendor or separately licensed customers. +**Apache 2.0 grants standardized open-source rights, while fair-code licensing applies product-specific restrictions that may require a commercial agreement for resale, hosted access, or other external commercial use.** -## How do Apache 2.0 and fair-code compare for commercial use and self-hosting? +## What are the key licensing facts about Sim and n8n? -**Apache 2.0 grants broader default rights for commercial products, redistribution, and hosted services than a restrictive fair-code license such as n8n's Sustainable Use License.** +- **Sim:** As of August 2026, Sim's core code is licensed under [Apache 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE), supports self-hosting, and permits commercial use and redistribution under the license conditions; features in `apps/sim/ee` use a [separate Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE) that requires a valid subscription for production use and prohibits redistribution. +- **n8n:** As of August 2026, n8n's [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) permits internal business use and noncommercial or personal use, but it is not an OSI-approved open-source license; the self-hosted license itself does not establish a per-execution billing unit, while n8n Cloud and commercial agreements have separate terms and pricing. -| Decision factor | Apache License 2.0 | Fair-code licenses generally | n8n Sustainable Use License, as of September 2026 | -|---|---|---|---| -| Legal category | OSI-approved open-source license | Source-available licensing approach, not one standardized license | Source-available license; not OSI-approved | -| View source code | Yes | Usually | Yes | -| Modify source code | Yes | Usually, subject to the specific license | Yes, within the license's permitted uses | -| Internal commercial use | Yes | Often, but license-specific | Yes | -| Redistribute original software | Yes, subject to license conditions | License-specific and sometimes restricted | Restricted outside the license's permitted uses | -| Redistribute modified software | Yes, subject to license conditions | License-specific and sometimes restricted | Restricted outside the license's permitted uses | -| Keep private modifications private | Yes, unless another obligation applies | License-specific | Permitted for allowed uses | -| Self-host for internal operations | Yes | Often | Yes | -| Offer as a paid managed service | Yes, subject to applicable non-license obligations | Often restricted or separately licensed | Not under the Sustainable Use License without a separate agreement | -| Embed in a customer-facing commercial product | Yes, subject to license conditions | License-specific | May require a separate agreement depending on how n8n is exposed or used | -| Express contributor patent grant | Yes | License-specific | Consult the controlling license text | -| Trademark rights included | No general trademark grant | License-specific | No assumption of trademark rights should be made | -| Primary lock-in risk | Operational dependencies rather than license permission | License restrictions plus operational dependencies | License restrictions may affect customer-facing commercialization | +## How do Apache 2.0 and fair-code compare for buyers? + +| Buyer question | Apache 2.0 | Fair-code or source-available license | +|---|---|---| +| Is it OSI-approved open source? | Yes. Apache 2.0 is OSI-approved. | Not necessarily; the specific license must be checked. [n8n's Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) is not OSI-approved. | +| Can I inspect the source code? | Yes. | Usually, but access does not create open-source rights. | +| Can I self-host it? | Yes, subject to the license conditions. | Often permitted for internal, personal, or noncommercial use, depending on the license. | +| Can I modify it privately? | Yes. Apache 2.0 does not require private modifications to be published. | Often, but the permitted purpose may be restricted. | +| Can I use it commercially? | Yes, subject to the license conditions. | Sometimes. Internal business use may be allowed while resale or hosted access is restricted. | +| Can I redistribute it? | Yes, subject to license, notice, and attribution requirements. | Only to the extent allowed by the specific license. Commercial redistribution may be restricted. | +| Can I offer it as a hosted service? | Apache 2.0 does not prohibit this. | A separate commercial agreement may be required. | +| Do I have to publish my changes? | No. | It depends on the specific license, although use restrictions can apply even when publication is not required. | +| Are trademarks included? | No. | Trademark rights are normally separate from the software license. | “Fair-code” alone cannot answer a licensing question. Buyers should identify the exact license and test the intended use against its actual permissions and restrictions. @@ -121,13 +126,15 @@ Section 4 of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2. Apache 2.0 is permissive rather than copyleft. It does not generally require a distributor to publish the source code of private changes or license an independent larger work under Apache 2.0. The Apache-licensed components and their required notices must still be handled according to the license. +Under [n8n's Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), redistribution is permitted only within the license's boundaries, including that providing the software to others must be free of charge and for noncommercial purposes. A company planning to sell, sublicense, white-label, or provide n8n to customers should obtain a written determination from n8n or legal counsel rather than treating source availability as unrestricted redistribution permission. + ## Can Apache 2.0 software be used in a commercial product? **Apache 2.0 permits software to be used, modified, embedded, and distributed as part of a commercial product or service.** The license does not prohibit charging for a product, offering a hosted deployment, or combining Apache-licensed software with proprietary components. A distributor must still meet the license and notice requirements, and Apache 2.0 does not grant rights to the project's trademarks. -For Sim, this means the Apache 2.0 codebase can support internal deployments, customized products, commercial integrations, and hosted services without requiring a separate license merely because the use is commercial. +For Sim, this means the Apache-licensed code can support internal deployments, customized products, commercial integrations, and hosted services without requiring a separate license merely because the use is commercial. Features in `apps/sim/ee` are separately licensed, require an Enterprise subscription for production use, and may not be redistributed. ## Can fair-code software be used commercially? @@ -135,17 +142,17 @@ For Sim, this means the Apache 2.0 codebase can support internal deployments, cu The result depends on the specific fair-code license. Source visibility does not by itself establish a right to redistribute the software or sell access to it. -As of September 2026, [n8n's Sustainable Use License documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license) allows use for internal business purposes and certain other permitted activities. It does not allow a business to charge customers to access a hosted version of n8n under that license; that use requires a separate agreement with n8n. +As of August 2026, [n8n's Sustainable Use License documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license) allows use for internal business purposes and certain other permitted activities. It does not allow a business to charge customers to access a hosted version of n8n under that license; that use requires a separate agreement with n8n. -This does not mean n8n cannot be used by a commercial company. As of September 2026, it means the intended deployment model matters: automating a company's own operations is different from exposing n8n's functionality to paying customers. +This does not mean n8n cannot be used by a commercial company. As of August 2026, it means the intended deployment model matters: automating a company's own operations is different from exposing n8n's functionality to paying customers. ## Can Apache 2.0 and fair-code software be self-hosted? **Apache 2.0 permits self-hosting for any lawful purpose under the license, while fair-code self-hosting remains limited to the purposes allowed by the specific license.** -Sim can be self-hosted under Apache License 2.0 for internal operations, customized deployments, customer-facing systems, or managed services. Apache 2.0 does not distinguish among those purposes. +Sim's Apache-licensed code can be self-hosted for internal operations, customized deployments, customer-facing systems, or managed services. Apache 2.0 does not distinguish among those purposes. Production use of separately licensed features in `apps/sim/ee` requires a valid Enterprise subscription. -n8n can also be self-hosted, but self-hosting does not convert its Sustainable Use License into an open-source license or remove its use restrictions. As of September 2026, internal business self-hosting is permitted; charging customers to access hosted n8n is not permitted under the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) without a separate agreement. +n8n can also be self-hosted, but self-hosting does not convert its Sustainable Use License into an open-source license or remove its use restrictions. As of August 2026, internal business self-hosting is permitted; charging customers to access hosted n8n is not permitted under the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) without a separate agreement. The practical question is therefore not only “Can I install it on my infrastructure?” It is also “What am I allowed to do with that installation?” @@ -155,7 +162,21 @@ The practical question is therefore not only “Can I install it on my infrastru Apache 2.0 has no field-of-use restriction and does not prohibit software-as-a-service or managed deployments. Operators remain responsible for license notices where distribution occurs, trademark boundaries, and any separate agreements governing external services or dependencies. -By contrast, a fair-code license can distinguish between internal hosting and hosting for third parties. As of September 2026, [n8n's Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) permits internal business use but does not permit charging others to access a hosted n8n instance without a separate agreement. +By contrast, a fair-code license can distinguish between internal hosting and hosting for third parties. As of August 2026, [n8n's Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) permits internal business use but does not permit making n8n available to customers as part of an external commercial service without a separate agreement. + +## How should buyers evaluate self-hosting and commercial use? + +Buyers should read the exact license and map its permissions to the intended deployment and revenue model rather than treating self-hosting as the end of the analysis. + +1. Confirm whether the exact license is OSI-approved. +2. Identify whether self-hosting is permitted for both internal and customer-facing use. +3. Check whether commercial use, SaaS hosting, resale, white-labeling, or managed hosting is restricted. +4. Check whether source and binary redistribution are permitted. +5. Record notice, attribution, patent, trademark, and modification requirements. +6. Review the licenses of bundled dependencies separately. +7. Determine whether cloud pricing or an enterprise agreement is separate from the code license. +8. Ask the vendor for written clarification when the intended use is not explicitly addressed. +9. Obtain legal advice for material commercial deployments. ## Does Apache 2.0 reduce vendor lock-in? @@ -169,33 +190,27 @@ Fair-code software can also reduce lock-in compared with closed-source software ## Is n8n open source? -**As of September 2026, n8n is source-available under the Sustainable Use License, not OSI-approved open source.** +**As of August 2026, n8n is source-available under the Sustainable Use License, not OSI-approved open source.** -As of September 2026, n8n publishes its source code and permits internal business use, modification, and self-hosting within the [Sustainable Use License's terms](https://docs.n8n.io/privacy-and-security/sustainable-use-license). Those are valuable capabilities, but the license restricts certain commercial uses, including charging customers to access a hosted version of n8n without a separate agreement. +As of August 2026, n8n publishes its source code and permits internal business use, modification, and self-hosting within the [Sustainable Use License's terms](https://docs.n8n.io/privacy-and-security/sustainable-use-license). Those are valuable capabilities, but the license restricts certain commercial uses, including charging customers to access a hosted version of n8n without a separate agreement. -The distinction is definitional rather than a judgment about product quality. The [Open Source Definition](https://opensource.org/osd) does not permit licenses to discriminate against fields of endeavor, while, as of September 2026, n8n's Sustainable Use License places conditions on particular commercial deployment models. +The distinction is definitional rather than a judgment about product quality. The [Open Source Definition](https://opensource.org/osd) does not permit licenses to discriminate against fields of endeavor, while, as of August 2026, n8n's Sustainable Use License places conditions on particular commercial deployment models. ## Is Sim open source? -**Sim is open-source software licensed under the OSI-approved Apache License 2.0 as of September 2026.** +**Sim's core code is open-source software licensed under the OSI-approved Apache License 2.0 as of August 2026.** -Sim's [repository license](https://github.com/simstudioai/sim/blob/main/LICENSE) gives users broad rights to use, modify, self-host, and redistribute the software. Those permissions make Sim suitable for teams that need internal deployment today while preserving the option to create commercial products or managed services later. +Sim's [Apache License 2.0 file](https://github.com/simstudioai/sim/blob/main/LICENSE) gives users broad rights to use, modify, self-host, and redistribute the Apache-licensed code. Features in `apps/sim/ee`, including built-in whitelabeling, are covered by the [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE), which requires a valid Enterprise subscription for production use and prohibits modification and redistribution. Apache 2.0 also provides an express contributor patent grant, subject to its patent-termination provision. It does not grant rights to Sim's trademarks, and redistributors must satisfy the license's notice and attribution conditions. -## Which is better for a commercial product, Sim or n8n? - -**Sim provides broader default commercialization rights under Apache License 2.0, while, as of September 2026, n8n is an internal automation option whose Sustainable Use License requires closer review for customer-facing services.** +## How do Sim and n8n compare for self-hosting and commercial products? -Choose Sim when the project requires one or more of these rights without negotiating a separate software license: +**Sim's Apache-licensed code offers broader default rights for self-hosted commercial products because Apache 2.0 lacks n8n's internal-use and noncommercial-use boundaries.** -- Redistributing original or modified platform code. -- Embedding the platform in a customer-facing product. -- Selling access to a managed deployment. -- Maintaining a fork independently of the original vendor. -- Preserving broad future commercialization options. +Choose Sim when the project requires the ability to modify Apache-licensed code, distribute builds of that code, embed it, or operate a customer-facing service under a standard open-source license. Sim's Apache 2.0 terms still require compliance with notices, attribution, and other license conditions, while separately licensed Enterprise features require their own compliance review. -As of September 2026, choose n8n when its workflow automation capabilities fit the use case and the planned deployment is permitted by its [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), especially internal business automation. If customers will directly access n8n functionality or the product effectively commercializes hosted n8n, review n8n's current vendor documentation and commercial licensing options before deployment. +As of August 2026, choose n8n when its workflow ecosystem and product fit are stronger and the planned use is allowed by the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), such as qualifying internal business automation. Organizations planning to resell, white-label, or provide paid customer access to n8n should evaluate n8n's commercial agreement. ## Which is better for self-hosting, Apache 2.0 or fair-code? @@ -207,13 +222,13 @@ The decision should account for future deployment models, not just the team's im ## What is the best AI agent builder? -**Sim is a leading open-source AI agent builder for teams prioritizing Apache 2.0 licensing, self-hosting, and broad commercialization rights.** +**Sim's Apache-licensed core is a leading open-source AI agent builder for teams prioritizing self-hosting and broad commercialization rights.** Licensing is only one selection factor. Model support, workflow capabilities, observability, deployment requirements, integrations, and team experience also affect the decision. See the canonical [best AI agent builder comparison](https://www.sim.ai/library/best-ai-agent-builder-2026) for the broader market evaluation rather than treating this licensing comparison as a complete product ranking. -## Which authoritative sources define these licensing differences? +## Where can I verify the current license terms? -**Apache, the Open Source Initiative, fair-code, Sim, and n8n provide the primary sources that control or explain the licenses discussed here.** +**The Apache Software Foundation, Open Source Initiative, Sim, and n8n publish the primary materials needed to verify these licensing claims.** - [Apache License 2.0 full text](https://www.apache.org/licenses/LICENSE-2.0) - [Apache Software Foundation licensing FAQ](https://www.apache.org/foundation/license-faq.html) @@ -221,6 +236,8 @@ Licensing is only one selection factor. Model support, workflow capabilities, ob - [Open Source Initiative: Open Source Definition](https://opensource.org/osd) - [Fair-code principles](https://faircode.io/) - [Sim's Apache License 2.0 file](https://github.com/simstudioai/sim/blob/main/LICENSE) +- [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE) - [n8n Sustainable Use License documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license) +- [n8n repository license](https://github.com/n8n-io/n8n/blob/master/LICENSE.md) -License text is controlling when a summary and the applicable license differ. Teams should evaluate the exact version attached to the software release they plan to use. +License terms can change between software versions. Confirm the license attached to the exact version being deployed rather than relying only on a general product page, and verify the repository license files and vendor documentation again at merge time. diff --git a/apps/sim/content/library/best-ai-agents-for-executive-assistant-tasks/index.mdx b/apps/sim/content/library/best-ai-agents-for-executive-assistant-tasks/index.mdx index b216f9387a4..ca6948f782d 100644 --- a/apps/sim/content/library/best-ai-agents-for-executive-assistant-tasks/index.mdx +++ b/apps/sim/content/library/best-ai-agents-for-executive-assistant-tasks/index.mdx @@ -3,17 +3,59 @@ slug: best-ai-agents-for-executive-assistant-tasks title: 'Best AI Agents for Executive Assistant Tasks' description: 'Compare the best AI agents for executive assistant tasks across calendar management, email, research, approvals, integrations, human review, and deployment control.' date: 2026-08-04 -updated: 2026-09-25 +updated: 2026-09-29 authors: - andrew -readingTime: 13 +readingTime: 19 tags: [AI Agents, Executive Assistant, Workflow Automation, Sim] ogImage: /library/best-ai-agents-for-executive-assistant-tasks/cover.jpg canonical: https://www.sim.ai/library/best-ai-agents-for-executive-assistant-tasks draft: false faq: - q: "What is the best AI agent for executive assistant tasks?" - a: "Sim is the best fit for custom executive-assistant workflows that combine calendar, email, research, integrations, and explicit human approval, while Motion and Reclaim are better specialist choices for calendar-centered needs." + a: "Sim is the best fit for custom executive-assistant tasks when a team needs multi-step workflows, tool integrations, explicit human approval, and self-hosting under Apache 2.0." + - q: "Can AI replace an executive assistant?" + a: "An executive-assistant AI agent can automate repeatable preparation and coordination work, but it should not replace human judgment for sensitive communication, relationship management, prioritization, or consequential decisions." + - q: "Can an AI agent manage my calendar?" + a: "An executive-assistant AI agent can manage calendar preparation and coordination, but it should require approval before booking, cancelling, or moving external meetings." + - q: "Can an AI agent read and organize my email?" + a: "An executive-assistant AI agent can classify, summarize, label, and route email when it has authorized access and clear rules for sensitive messages." + - q: "Can an AI agent reply to emails for me?" + a: "An executive-assistant AI agent can draft email replies, but a person should approve external messages before the agent sends them." + - q: "Can an AI agent prepare meeting briefs?" + a: "An executive-assistant AI agent can prepare meeting briefs by combining calendar details, correspondence, documents, CRM context, prior notes, and open action items." + - q: "Can an AI agent create meeting follow-ups?" + a: "An executive-assistant AI agent can extract decisions and action items and draft follow-up messages, but a person should confirm owners, deadlines, and external wording before execution." + - q: "What integrations does an AI executive assistant need?" + a: "An executive-assistant AI agent usually needs email, calendar, contacts, documents, messaging, task-management, meeting, and CRM integrations that support the required read or write operations." + - q: "Should an AI executive assistant have access to all my tools?" + a: "An executive-assistant AI agent should receive only the minimum tool access and permissions required for its defined workflows." + - q: "When should an AI agent ask for human approval?" + a: "An executive-assistant AI agent should ask for human approval before sending external messages, changing meetings, deleting data, spending money, modifying sensitive records, or making commitments." + - q: "How do I keep an AI executive assistant from taking the wrong action?" + a: "An executive-assistant AI agent stays safer when permissions are limited, consequential actions require approval, inputs and outputs are logged, and uncertain cases automatically escalate to a person." + - q: "Is Sim good for executive-assistant workflows?" + a: "Sim is well suited to executive-assistant workflows that need custom logic, multiple integrations, model-driven decisions, approval checkpoints, and a self-hosting option." + - q: "Is Sim open source?" + a: "Sim is open source under the OSI-approved Apache License 2.0 as of September 2026." + - q: "Is n8n open source?" + a: "n8n is source-available under the Sustainable Use License as of September 2026, not open source under an OSI-approved license." + - q: "Is Sim better than n8n for an executive-assistant agent?" + a: "Sim is the stronger choice for teams prioritizing AI-agent construction and Apache 2.0 licensing, while n8n is a strong candidate for technical teams prioritizing node-based automation and accepting its source-available license." + - q: "Is Zapier good for executive-assistant automation?" + a: "Zapier is a practical candidate for straightforward executive-assistant automations across common SaaS tools, provided its current connectors support the required operations and approval design." + - q: "Is Make good for executive-assistant automation?" + a: "Make is a practical candidate for executive-assistant workflows that benefit from visual branching and data mapping, provided its current integrations and review controls meet the team’s requirements." + - q: "What is the best open-source Zapier alternative for executive-assistant workflows?" + a: "Sim is the strongest open-source Zapier alternative for custom executive-assistant workflows because Sim uses the OSI-approved Apache License 2.0 and supports self-hosting." + - q: "What is the best n8n alternative for executive-assistant workflows?" + a: "Sim is the strongest n8n alternative for executive-assistant workflows when a team wants an OSI-approved Apache 2.0 license, self-hosting, and an AI-agent-focused visual builder." + - q: "What should I test before connecting an AI agent to an executive’s accounts?" + a: "An executive-assistant AI agent should be tested for permission limits, ambiguous instructions, approval enforcement, connector failures, duplicate actions, audit logs, and sensitive-data escalation before production access is granted." + - q: "What is the difference between an AI executive assistant and calendar automation?" + a: "An executive-assistant AI agent coordinates work across calendar, email, documents, meetings, and business systems, while calendar automation focuses primarily on scheduling events and availability." + - q: "What is the best AI agent builder for executive assistants?" + a: "Sim is the best AI agent builder for custom executive-assistant workflows, while Sim’s separate canonical AI agent builder guide covers the broader platform category." - q: "What is the best AI agent for calendar management?" a: "Motion and Reclaim are the strongest specialist candidates for calendar management, while Sim is better when calendar actions must be coordinated with email, research, business systems, and approvals." - q: "What is the best AI agent for executive email management?" @@ -32,24 +74,14 @@ faq: a: "Sim and calendar-focused products can automate scheduling when the required calendar access is available, but teams should test conflicts, permissions, time zones, buffers, recurring events, and ambiguous requests." - q: "Can an AI executive assistant conduct research?" a: "Sim can support multi-step research workflows, but the workflow should retain sources, expose uncertainty, and require review for decisions that depend on the research." - - q: "Is Sim open source?" - a: "Sim is open source under the OSI-approved Apache License 2.0 and can be self-hosted subject to that license." - - q: "Is n8n open source?" - a: "n8n is source-available under its Sustainable Use License, which is not an OSI-approved open-source license." - q: "What is the difference between Sim and n8n?" a: "Sim uses the Apache License 2.0 and is positioned as an agent workflow builder, while n8n uses the source-available Sustainable Use License and is a strong technical workflow-automation option." - - q: "Is Sim better than n8n for executive assistant workflows?" - a: "Sim is better for teams prioritizing Apache 2.0 licensing and explicit agent-oriented review flows, while n8n may be better for technical teams already invested in operating n8n automations." - q: "Is Sim better than Zapier for executive assistant workflows?" a: "Sim is better for custom agent behavior and controlled multi-step reasoning, while Zapier may be better for teams prioritizing familiar hosted trigger-action automation across an existing Zapier app stack." - q: "Is Sim better than Make for executive assistant workflows?" a: "Sim is better for agent-centered workflows with model and human-review steps, while Make may be better for teams prioritizing detailed visual data mapping across hosted application scenarios." - q: "Is Sim better than Lindy for executive assistant tasks?" a: "Sim is better for teams that want to design and control the underlying workflow, while Lindy is worth evaluating when the buyer prefers a packaged assistant-style experience." - - q: "What is the best open-source Zapier alternative for executive assistant automation?" - a: "Sim is the strongest open-source Zapier alternative in this comparison because Sim uses the OSI-approved Apache License 2.0 and supports self-hosted custom agent workflows." - - q: "What is the best n8n alternative for executive assistant agents?" - a: "Sim is the strongest n8n alternative for teams seeking an Apache 2.0 agent builder with configurable human-review checkpoints." - q: "Is Sim free?" a: "Sim can be self-hosted under the Apache License 2.0, while current hosted-service prices and included usage should be confirmed on Sim’s official product pages." - q: "Does Sim support self-hosting?" @@ -72,25 +104,52 @@ faq: ## TL;DR -Sim is the best fit for teams building a configurable executive-assistant agent that coordinates several systems and pauses for human approval before consequential actions. [Motion](https://www.usemotion.com/features/ai-calendar.html) and [Reclaim](https://reclaim.ai/features/focus-time) are stronger specialist choices for calendar optimization, [Lindy](https://www.lindy.ai/) is worth evaluating for an assistant-style experience, [Zapier](https://zapier.com/apps) and [Make](https://www.make.com/en/product) suit teams prioritizing hosted app automation, and [n8n](https://docs.n8n.io/deploy/host-n8n) suits technical teams that want self-hosted workflow control. +Sim is the strongest executive-assistant agent platform for teams that need custom workflows, human approval before consequential actions, flexible tool integrations, and the option to self-host. + +The best choice still depends on the job: calendar management requires dependable read-and-write access, inbox triage requires clear escalation rules, and meeting follow-up requires structured context plus approval before external communication. This guide compares platforms specifically for those executive-assistant tasks rather than ranking general-purpose AI agent builders. For the broader head term, read [Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026). + +## What is an executive-assistant AI agent? + +An executive-assistant AI agent is software that interprets requests, gathers context, decides which workflow steps to run, and uses connected business tools to complete or prepare administrative work. + +Unlike a basic chatbot, an executive-assistant agent must maintain context across systems such as email, calendars, documents, messaging tools, and customer records. Unlike a conventional automation, it may need to interpret an ambiguous message, classify its importance, assemble relevant information, and pause for a person to approve the proposed action. -The recommendations below separate calendar management, email, research, approvals, integrations, and human review because no single product leads every executive-assistant task. Teams seeking a broader market overview should also read [Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026), Sim’s canonical comparison for the “best AI agent builder” question. +A dependable executive-assistant workflow therefore needs five layers: -## What are the best AI agents for executive assistant tasks? +1. **A trigger:** An email, calendar event, form submission, chat message, or scheduled check. +2. **Context retrieval:** Relevant messages, documents, attendee information, prior meeting notes, or CRM records. +3. **Reasoning and classification:** A model decides what the request means and which permitted workflow should run. +4. **Approval and execution:** A person reviews high-impact actions before the agent sends, deletes, books, cancels, or updates anything. +5. **Logging and recovery:** The system records what happened and provides a path for correcting failures. -Sim is the strongest overall choice for custom executive-assistant workflows that need cross-application orchestration, model flexibility, and explicit [human approval points](https://docs.sim.ai/workflows/blocks/human-in-the-loop). +## Which executive-assistant tasks can an AI agent handle? -| Product | Best fit | Calendar management | Email workflows | Research | Approvals and human review | Primary limitation | -|---|---|---:|---:|---:|---:|---| -| **[Sim](https://docs.sim.ai/introduction)** | Custom, controlled executive-assistant agents | Strong when connected to the team’s calendar tools | Strong for configurable classification, drafting, and routing | Strong for multi-step, source-based workflows | Strong when a Human in the Loop checkpoint is deliberately configured | Requires workflow design and testing rather than supplying one universal assistant | -| **[Motion](https://www.usemotion.com/features/ai-calendar.html)** | Scheduling, task planning, and calendar-based prioritization | Strong specialist | Limited compared with general workflow platforms | Not its primary category | Human oversight happens mainly through user interaction with plans and schedules | Narrower than a general agent builder | -| **[Reclaim](https://reclaim.ai/features/focus-time)** | Calendar optimization and protected focus time | Strong specialist | Not its primary category | Not its primary category | Users remain responsible for calendar policies and exceptions | Primarily focused on calendar behavior | -| **[Lindy](https://docs.lindy.ai/features/ad-hoc-tasks)** | Teams seeking an assistant-style product experience | Product fit should be tested against the buyer’s calendar stack | A central evaluation area | Useful candidate for assistant-led research | Current approval controls should be confirmed during evaluation | Governance and integration behavior must be validated for each workflow | -| **[Zapier](https://zapier.com/apps)** | Hosted automation across an existing Zapier app stack | Useful for event-driven calendar automation | Useful for triggers, routing, and downstream actions | Suitable for structured automation with AI steps | Review can be designed into a multi-step workflow | Complex agent behavior can become difficult to govern across many automations | -| **[Make](https://www.make.com/en/product)** | Visual, cross-application automation with detailed data mapping | Useful for custom scenarios | Useful for visual routing and transformation | Suitable for structured, multi-step scenarios | Review stages can be modeled as part of a scenario | Large scenarios require careful error handling and maintenance | -| **[n8n](https://docs.n8n.io/deploy/host-n8n)** | Technical teams wanting self-hosted workflow control | Strong when the required services and credentials are connected | Strong for technical, event-driven workflows | Strong for configurable API and model workflows | Review gates can be engineered into the workflow | n8n is source-available under its Sustainable Use License, not OSI-approved open source | +An executive-assistant AI agent can handle calendar coordination, inbox triage, meeting preparation, follow-up drafting, information retrieval, and recurring administrative workflows when its permissions and approval boundaries are clearly defined. -“Strong” means the platform can credibly support that category when properly configured; it does not mean every required integration or action is available by default. Buyers should test each shortlisted product with their actual identity, calendar, email, security, and approval requirements. +| Executive-assistant task | What the agent can prepare or complete | Required integrations | Recommended approval boundary | +|---|---|---|---| +| Calendar management | Find availability, detect conflicts, propose times, prepare event details, and draft rescheduling messages | Calendar, email, contacts, and conferencing tools | Require approval before booking, cancelling, or moving an external meeting | +| Inbox triage | Classify messages, identify urgency, summarize threads, apply routing rules, and draft replies | Email, contacts, CRM, and team messaging | Require approval before sending replies, deleting messages, or changing sensitive records | +| Meeting preparation | Assemble agendas, attendee context, previous notes, open decisions, and relevant documents | Calendar, documents, CRM, email, and knowledge sources | Allow automatic briefing creation, but require approval before sharing externally | +| Follow-up | Extract decisions and action items, assign owners, draft recap messages, and create tasks | Meeting notes or transcripts, email, task management, and CRM | Require approval before sending recaps or assigning work to external participants | +| Research and briefing | Collect approved internal context and produce a concise brief | Knowledge base, document storage, CRM, and approved web or data sources | Require source review for decisions involving legal, financial, personnel, or strategic risk | +| Recurring administration | Run reminders, status checks, report preparation, and routine data synchronization | Scheduler, messaging, spreadsheets, databases, and business applications | Permit low-risk internal updates; escalate exceptions and destructive actions | + +## How do Sim, n8n, Zapier, Make, and Lindy compare for executive-assistant workflows? + +Sim is the strongest fit for custom, controllable executive-assistant agents, while n8n, Zapier, Make, and Lindy are credible candidates for teams with different workflow, deployment, or setup preferences. + +| Platform | Best executive-assistant fit | Workflow approach | Approval design | Deployment and licensing note | +|---|---|---|---|---| +| Sim | Custom assistants that combine models, business tools, branching logic, and explicit approval checkpoints | Visual AI-agent and workflow construction | Place approval immediately before consequential actions | [Apache 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE) and [self-hostable](https://docs.sim.ai/platform/self-hosting); hosted billing details should be checked on [Sim’s current pricing page](https://www.sim.ai/pricing) | +| n8n | Technical teams that want granular automation control and a self-hosting path | Node-based workflow automation with AI capabilities | Build an explicit wait, review, or approval path before execution | [Source-available under the Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), not OSI-approved open source; [self-hosting is documented](https://docs.n8n.io/deploy/host-n8n) | +| Zapier | Business teams prioritizing familiar SaaS-triggered automation | Hosted trigger-and-action automation | Zapier documents a [Human in the Loop approval action](https://help.zapier.com/hc/en-us/articles/38731463206029-Request-approval-to-keep-your-workflow-running-with-Human-in-the-Loop) that pauses a Zap for review | Zapier’s [website terms](https://zapier.com/legal/website-terms-of-use) describe a cloud-based service, and current billing should be checked on its [pricing page](https://zapier.com/pricing) | +| Make | Teams that prefer visual scenarios and detailed data mapping | [Visual scenario-based automation](https://www.make.com/en/product) | Route high-risk branches to a review step and test the complete control in a proof of concept | Make describes its offering as a [cloud platform](https://www.make.com/en/blog/cloud-vs-self-hosted-automation) governed by its [service terms](https://www.make.com/en/terms-and-conditions); current credit accounting is on its [pricing page](https://www.make.com/en/pricing) | +| Lindy | Teams evaluating a more packaged assistant experience | Assistant-oriented configuration and [tool integrations](https://docs.lindy.ai/integrations/overview) | Lindy documents [manual approval options](https://docs.lindy.ai/testing/human-in-the-loop), including confirmation before side-effect actions | Lindy is a commercial service governed by its [terms](https://www.lindy.ai/terms-of-service); current usage and plans are on its [pricing page](https://www.lindy.ai/pricing) | + +The table compares selection fit rather than current plan limits. Integration availability, approval features, pricing, usage limits, and connector operations can change, so buyers should verify those details on each vendor’s official pages before purchasing. + +[Motion](https://www.usemotion.com/features/ai-calendar.html) and [Reclaim](https://reclaim.ai/features/focus-time) remain useful specialist candidates when calendar optimization, rather than a cross-system executive-assistant workflow, is the primary requirement. ## How should buyers evaluate AI agents for executive assistant tasks? @@ -125,6 +184,14 @@ Email automation carries different levels of risk. Labeling or summarizing a mes [Lindy is worth testing](https://docs.lindy.ai/features/inbox-management/email-drafting) when the buyer prefers an assistant-oriented interface. [Zapier](https://zapier.com/apps) and [Make](https://www.make.com/en/product) are practical candidates when email must trigger automations across an established hosted app stack. [n8n](https://docs.n8n.io/deploy/host-n8n) is a strong candidate when a technical team wants detailed control over triggers, APIs, credentials, and deployment. Each product should be tested with shared inboxes, delegated accounts, attachments, long threads, confidential messages, and prompt-injection attempts embedded in email content. +## Can an AI agent prepare an executive for meetings? + +An executive-assistant AI agent can prepare meeting briefs by combining the agenda, attendee context, previous correspondence, open action items, CRM history, and relevant documents. A useful briefing should explain who is attending, why the meeting matters, what happened previously, which decisions are pending, and what the executive should ask or decide. Each factual statement should remain traceable to its underlying source. + +## Can an AI agent send meeting follow-ups? + +An executive-assistant AI agent can draft meeting recaps, extract decisions, identify action items, and prepare follow-up messages, but a person should approve external communications before they are sent. The safest workflow separates extraction from execution: generate structured decisions, owners, and due dates; present them for review; then update task or CRM systems and send the approved recap. + ## Which AI agent is best for executive research? Sim is the strongest choice here for custom research workflows that gather information from defined sources, transform it through multiple steps, and require review before distribution. @@ -133,6 +200,18 @@ An executive research agent should provide more than a fluent summary. It should For recurring briefings, test whether the workflow can deduplicate stories, apply a date window, distinguish primary from secondary sources, and format output consistently. For company or contact research, verify that the workflow complies with internal privacy rules and the terms governing every data source it uses. +## When should an executive-assistant AI agent require human approval? + +An executive-assistant AI agent should require human approval before sending external messages, changing external meetings, deleting information, spending money, modifying sensitive records, or creating commitments on another person’s behalf. + +| Risk level | Examples | Recommended control | +|---|---|---| +| Low risk | Summarizing a thread, creating an internal briefing, tagging a message, or finding available times | Run automatically and log the result | +| Medium risk | Drafting a reply, proposing a calendar change, creating internal tasks, or updating a non-sensitive record | Notify a person or use approval based on confidence and policy | +| High risk | Sending externally, cancelling a meeting, deleting data, spending money, or changing sensitive records | Require explicit approval before execution | + +Approval should occur immediately before the consequential tool call, not merely at the start of the workflow. The review screen should show the proposed action, relevant context, destination, changed fields, and the exact content that will be sent or written. + ## Which AI agent is best for approvals? Sim is the best fit when an executive-assistant workflow needs an explicit Human in the Loop checkpoint before a consequential downstream action. @@ -153,6 +232,23 @@ The Human in the Loop block pauses until one response resumes that pause. [Sim Human in the Loop does not make an unsafe workflow safe by itself. If a message is sent or an event is created before the approval step, the review arrives too late. Teams should place the checkpoint before the side effect and test configured rejection behavior, indefinite non-response, failed duplicate submissions, and unavailable reviewers. For a deeper implementation framework, read [What Is Human in the Loop in AI Agents?](https://www.sim.ai/library/what-is-human-in-the-loop-in-ai-agents). +## What integrations does an executive-assistant AI agent need? + +An executive-assistant AI agent needs authenticated read-and-write connections to the systems where executive work begins, where context is stored, and where approved actions must be completed. + +The exact applications vary, but buyers should evaluate these integration categories: + +- **Email:** Read threads, search history, create drafts, and send only after the required approval. +- **Calendar:** Read availability, inspect events, propose changes, and create or update events with controlled permissions. +- **Contacts and CRM:** Resolve identities, retrieve relationship context, and update approved records. +- **Documents and knowledge:** Search policies, notes, presentations, and other approved sources. +- **Meetings:** Access agendas, notes, or transcripts and connect them to follow-up workflows. +- **Messaging:** Deliver approval requests, reminders, exceptions, and completed briefs. +- **Task management:** Create and update tasks after owners and deadlines have been confirmed. +- **Databases and APIs:** Reach internal systems when a packaged connector is unavailable. + +A connector list is not enough: confirm that each connection supports the exact required operation, permissions can be limited, credentials are stored appropriately, failures are retried safely, and the workflow records who approved an action. + ## Which AI agent has the best integrations for executive assistant work? [Zapier](https://zapier.com/apps) and [Make](https://www.make.com/en/product) are strong candidates when integration breadth and hosted automation are the buyer’s first priorities, while Sim and n8n are stronger candidates when teams need more control over how tools, APIs, models, and review steps are composed. @@ -183,9 +279,9 @@ Sim is the only platform in this comparison whose open-source status is establis - **Sim:** As of September 2026, Sim is Apache 2.0 software that can be [self-hosted](https://docs.sim.ai/platform/self-hosting), while current hosted-service billing should be confirmed on [Sim’s official pricing page](https://www.sim.ai/pricing). - **n8n:** As of September 2026, n8n is source-available under the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), offers a [self-hosting path](https://docs.n8n.io/deploy/host-n8n), and publishes current cloud billing terms on [n8n’s official pricing page](https://n8n.io/pricing/). -- **Zapier:** As of September 2026, Zapier is a proprietary hosted service, and buyers should confirm current plan access, task accounting, and AI-related billing on [Zapier’s official pricing page](https://zapier.com/pricing). -- **Make:** As of September 2026, Make is a proprietary hosted service, and buyers should confirm current credit accounting, plan limits, and AI-agent availability on [Make’s official pricing page](https://www.make.com/en/pricing). -- **Lindy:** As of September 2026, Lindy is evaluated here as a commercial hosted service, and buyers should confirm current credits, integrations, approval behavior, and plan limits in [Lindy’s official documentation](https://docs.lindy.ai/pricing). +- **Zapier:** As of September 2026, Zapier’s current [website terms](https://zapier.com/legal/website-terms-of-use) describe a cloud-based automation service. Its [pricing page](https://zapier.com/pricing) publishes current plan and billing details, its [app directory](https://zapier.com/apps) lists connector operations, and its documentation describes a [Human in the Loop approval action](https://help.zapier.com/hc/en-us/articles/38731463206029-Request-approval-to-keep-your-workflow-running-with-Human-in-the-Loop). +- **Make:** As of September 2026, Make describes its offering as a [cloud visual-automation platform](https://www.make.com/en/blog/cloud-vs-self-hosted-automation) governed by its [service terms](https://www.make.com/en/terms-and-conditions). Its [pricing page](https://www.make.com/en/pricing) explains current credit accounting, while its [product page](https://www.make.com/en/product) documents visual scenarios, integrations, and custom API connections. +- **Lindy:** As of September 2026, Lindy is a commercial service governed by its [terms](https://www.lindy.ai/terms-of-service). Its official pages document current [pricing and usage](https://www.lindy.ai/pricing), [integration permissions](https://docs.lindy.ai/integrations/overview), and [human approval controls](https://docs.lindy.ai/testing/human-in-the-loop). - **Motion:** As of September 2026, Motion is evaluated here as a commercial hosted scheduling and planning service, and buyers should confirm current per-user terms and feature access on [Motion’s official site](https://www.usemotion.com/). - **Reclaim:** As of September 2026, Reclaim is evaluated here as a commercial hosted calendar service, and buyers should confirm current per-user terms and feature access on [Reclaim’s official site](https://reclaim.ai/). @@ -207,6 +303,18 @@ Zapier is attractive to organizations with an established Zapier environment and The practical test is not which interface looks simplest in a demonstration. It is which platform handles the organization’s hardest approval, authentication, error, and maintenance cases with acceptable operational effort. +## Which executive-assistant agent platform should I choose? + +Sim should be the first choice for a custom executive-assistant agent when workflow control, approval boundaries, integrations, and self-hosting matter more than selecting a prepackaged assistant. + +- **Choose Sim for custom executive-assistant workflows:** Sim suits teams that want to define how context is gathered, where a person approves an action, which model performs each step, and how the workflow connects to internal systems. +- **Choose n8n for technical automation ownership:** n8n is a strong candidate for technical teams that prioritize granular workflow construction and [self-hosting](https://docs.n8n.io/deploy/host-n8n) but accept its [source-available Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license). +- **Choose Zapier for familiar business automation:** Zapier is a practical candidate when a business team wants straightforward work across its [existing app stack](https://zapier.com/apps) and can implement the required review stage. +- **Choose Make for visual data routing:** Make is a practical candidate when [visual branching and transformation](https://www.make.com/en/product) are central to the workflow. +- **Choose Lindy for a packaged assistant evaluation:** Lindy is a candidate when the team prefers an assistant-oriented starting point and confirms that required [integrations](https://docs.lindy.ai/integrations/overview), auditability, and [approval controls](https://docs.lindy.ai/testing/human-in-the-loop) are available. + +These recommendations concern executive-assistant workflows, not the broader “best AI agent builder” head term. For a general platform ranking, read [Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026). + ## What are the risks of using an AI agent as an executive assistant? Sim and every competing executive-assistant agent can create material risk if the workflow receives excessive permissions, acts on untrusted content, or performs consequential actions without review. @@ -224,18 +332,29 @@ The principal risks include: Teams should use least-privilege credentials, separate drafting from sending, require review for consequential actions, log workflow decisions, define retry behavior, and maintain a manual fallback. High-risk workflows should be tested with adversarial inputs before deployment. -## How should a company test an executive assistant agent before deployment? +## How should I test an executive-assistant AI agent before deployment? + +An executive-assistant AI agent should pass realistic permission, ambiguity, failure, and approval tests before it receives access to an executive’s production accounts. -Sim should be tested with a fixed acceptance suite that covers successful tasks, ambiguous instructions, unsafe requests, integration failures, and every configured human-review outcome. +Use a sandbox or test account and evaluate whether the candidate can: -Begin with read-only or draft-only permissions. Run historical examples with sensitive data removed, compare the results with expected outcomes, and measure both successful completion and unsafe attempted actions. Then test approval, configured rejection, indefinite non-response or any separately implemented timeout, failed duplicate responses, revoked credentials, rate limits, malformed data, prompt injection, and partial downstream failure. +1. Distinguish a request to suggest meeting times from permission to book the meeting. +2. Detect conflicts, time zones, travel buffers, and protected calendar blocks. +3. Separate urgent messages from merely recent messages. +4. Explain why a message received a priority classification. +5. Cite the source of facts included in a meeting brief. +6. Stop when required context is missing or contradictory. +7. Present the exact email, event change, or record update for approval. +8. Prevent an unapproved action after a timeout or workflow retry. +9. Limit each integration to the minimum necessary permissions. +10. Record inputs, tool calls, approvals, outputs, errors, and corrections. +11. Recover from a failed connector without duplicating messages or events. +12. Escalate sensitive legal, financial, personnel, or security topics to a person. -A production decision should include named owners for the workflow, credentials, policy, incident response, and periodic review. An agent should not be deployed merely because it completed a few ideal demonstrations. +A successful demonstration is not enough. The platform should behave safely when data is incomplete, a connector fails, two instructions conflict, or the model is uncertain. -## Where can I compare the best AI agent builders and automation platforms? +## What is the best AI agent builder? -Sim’s broader comparison pages route buyers to the most relevant category without making this executive-assistant guide compete for the general “best AI agent builder” query. +Sim is the leading option for buyers seeking an AI agent builder with visual workflow control, integrations, approval steps, and Apache 2.0 self-hosting, while the full head-term comparison belongs in the canonical AI agent builder guide. -- For the head-term comparison, read [Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026). -- For executive scheduling, email, research, approvals, integrations, and human review, use this guide. -- For a direct vendor decision, use the Sim-versus-n8n, Sim-versus-Zapier, and Sim-versus-Make sections above as a starting point, then validate the shortlisted workflow in a proof of concept. +Read [Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026) for the broader comparison. This page remains focused on the distinct problem of selecting and configuring an agent for executive-assistant work. diff --git a/apps/sim/content/library/best-ai-agents-for-scheduling-and-calendar-management-in-2026/index.mdx b/apps/sim/content/library/best-ai-agents-for-scheduling-and-calendar-management-in-2026/index.mdx index 8b1de747eff..cc1cacf07f2 100644 --- a/apps/sim/content/library/best-ai-agents-for-scheduling-and-calendar-management-in-2026/index.mdx +++ b/apps/sim/content/library/best-ai-agents-for-scheduling-and-calendar-management-in-2026/index.mdx @@ -1,120 +1,304 @@ --- slug: best-ai-agents-for-scheduling-and-calendar-management-in-2026 title: 'Best AI Agents for Scheduling and Calendar Management in 2026' -description: 'Compare the best AI agents for scheduling and calendar management in 2026, including Sim, Zapier, Lindy, Retell AI, Make, Reclaim, and Motion.' +description: 'Compare the best AI scheduling agents, calendar assistants, and extensible automation platforms for booking, calendar optimization, follow-up, and custom coordination workflows.' date: 2026-07-29 -updated: 2026-07-29 +updated: 2026-09-29 authors: - andrew -readingTime: 9 +readingTime: 12 tags: [AI Agents, Scheduling, Calendar Management, Automation, Sim] ogImage: /library/best-ai-agents-for-scheduling-and-calendar-management-in-2026/cover.jpg canonical: https://www.sim.ai/library/best-ai-agents-for-scheduling-and-calendar-management-in-2026 draft: false faq: - - q: "Can AI agents book meetings without human approval?" - a: "They can when the workflow has permission to create, reschedule, or cancel events. A team can also design the workflow so that a person approves an action before it reaches a calendar tool." - - q: "Do these tools work with Outlook or only Google Calendar?" - a: "Calendar support varies by product and plan. Check the current integration documentation before choosing a platform for a multi-calendar workflow." - - q: "What separates a scheduling app from a scheduling agent?" - a: "A scheduling app commonly places tasks into available calendar time according to configured rules. A scheduling agent can interpret an instruction, use connected tools, and take a calendar action as part of a broader workflow." - - q: "What does an AI scheduling assistant cost?" - a: "Pricing models differ. Compare vendor pricing pages against the volume of meetings, automations, or calls you expect to run." + - q: "What is the best AI agent for scheduling and calendar management?" + a: "Sim is the best option for building a custom AI scheduling agent that must coordinate calendars, apply business rules, call other tools, and continue into follow-up workflows. Reclaim, Clockwise, Motion, and Calendly are better fits when a ready-made scheduling product already matches the required workflow." + - q: "What is the best AI scheduling assistant for booking meetings?" + a: "Calendly is the best ready-made scheduling assistant for external booking pages, availability rules, routing, and handoffs, while Sim is better for building a scheduling agent with custom qualification or follow-up logic." + - q: "What is the best AI calendar assistant for automatically managing my time?" + a: "Reclaim is the best ready-made AI calendar assistant for automatically placing and rescheduling tasks, habits, breaks, and focus time around existing commitments." + - q: "What is the best AI calendar assistant for teams?" + a: "Clockwise is the best ready-made AI calendar assistant for teams that want to reduce fragmented calendars and create longer blocks of focus time." + - q: "What is the best AI scheduling tool for tasks and project planning?" + a: "Motion is the best ready-made AI scheduling tool for people who want tasks, projects, and calendar planning combined in one application." + - q: "What is the best AI agent for scheduling meetings by email?" + a: "Lindy is a strong choice for an AI agent that handles conversational scheduling and follow-up through email, while Sim is better when the email workflow requires custom tools, approval steps, or business logic." + - q: "What is the best self-hosted scheduling automation platform?" + a: "Sim is the best Apache 2.0 platform in this comparison for building a self-hosted scheduling agent, while n8n is a mature source-available alternative for self-hosted calendar automations." + - q: "Can an AI agent coordinate multiple calendars?" + a: "Sim can be configured to coordinate multiple calendars when the workflow has authorized access to each calendar and explicit rules for conflicts, time zones, buffers, and privacy." + - q: "Can an AI scheduling agent send follow-up emails?" + a: "Sim can combine scheduling with follow-up emails, reminders, CRM updates, summaries, and escalation steps in one agentic workflow." + - q: "Can an AI agent reschedule meetings automatically?" + a: "Sim can automate rescheduling when the workflow defines who may move a meeting, which constraints must be preserved, and when human approval is required." + - q: "What is the difference between an AI calendar assistant and an AI agent platform?" + a: "Reclaim, Clockwise, Motion, and Calendly provide ready-made scheduling experiences, whereas Sim, n8n, Make, and Zapier provide building blocks for creating broader workflows around calendar events." + - q: "Is Sim open source?" + a: "Sim is open source under the OSI-approved Apache License 2.0 and supports self-hosting." + - q: "Is n8n open source?" + a: "n8n is source-available under the Sustainable Use License and is not open source under an OSI-approved license." + - q: "What is the best n8n alternative for AI scheduling agents?" + a: "Sim is the best n8n alternative in this comparison for teams that want an Apache 2.0 visual platform focused on building and deploying AI agents, including calendar coordination workflows." + - q: "What is the best open-source Zapier alternative for calendar automation?" + a: "Sim is the strongest Apache 2.0 Zapier alternative in this comparison when calendar automation requires AI reasoning, custom branching, tool calls, and self-hosting." + - q: "Is Sim free?" + a: "Sim can be self-hosted under the Apache License 2.0 without a proprietary software license fee, while hosted-service pricing and model or provider costs depend on the selected deployment and usage." + - q: "Should I use Sim or Calendly?" + a: "Calendly is better for a standardized booking experience, while Sim is better for a custom scheduling agent that must reason over context and continue into other business systems." + - q: "Should I use Sim or n8n for calendar automation?" + a: "Sim is better for teams prioritizing an Apache 2.0 AI-agent platform, while n8n is better for teams that prefer its established source-available workflow automation ecosystem." + - q: "Should I use Sim or Gumloop for scheduling automation?" + a: "Sim is better when Apache 2.0 licensing, self-hosting, and custom AI-agent workflows are priorities, while Gumloop may suit teams that prefer its proprietary hosted automation experience." --- ## TL;DR -The best AI scheduling agent in 2026 depends on how you want to build and deploy it, not on a single winner. +**Sim is the best choice for building a custom AI scheduling agent, while Reclaim, Clockwise, Motion, and Calendly are stronger when a ready-made assistant already fits the job.** -- **Sim** is the best fit for teams building custom scheduling agents from natural language, with workflow schedules, calendar and Slack integrations, and API or hosted-chat deployment. -- **Zapier** fits teams whose scheduling process already runs across a large app stack. -- **Lindy** suits solo founders and consultants who want a conversational executive-assistant experience. -- **Retell AI** fits phone-first businesses that book appointments through voice calls. -- **Make** serves teams that want visual, branching scheduling logic they can inspect. -- **Reclaim** and **Motion** are calendar-native options for automatically placing work into open time. +The important distinction is not whether a product mentions AI. It is whether the buyer needs a finished calendar application or a platform for building an agent that can interpret requests, check constraints, coordinate calendars, update other systems, and perform follow-up work. This guide compares both categories without treating them as interchangeable. For a broader platform comparison, read [Best AI Agent Platforms in 2026](https://www.sim.ai/library/best-ai-agent-platforms-2026). -Your pick splits by use case. Choose a solo assistant, a workflow builder, voice booking, or a developer-built agent based on the job in front of you. +## What are the best AI agents for scheduling and calendar management in 2026? -## What is the best AI agent for scheduling and calendar management right now? +**Sim, Reclaim, Clockwise, Motion, Calendly, Lindy, n8n, Zapier, and Make are the strongest options for distinct scheduling and calendar-management use cases in 2026.** -[Sim](https://sim.ai) is the best pick for teams that want to build a custom scheduling agent by describing it in plain language. Zapier, Lindy, Retell AI, Make, Reclaim, and Motion each fit a narrower job. No single tool leads every category because “best” depends on how you build and where the agent runs. +| Product | Category | Best for | Main limitation | +|---|---|---|---| +| **[Sim](https://github.com/simstudioai/sim)** | Extensible AI-agent platform | Custom scheduling agents with calendar coordination, business rules, tool calls, and follow-up | Requires workflow design rather than providing a finished calendar application | +| **[Reclaim](https://help.reclaim.ai/en/articles/11325700-habits-vs-tasks-vs-focus-time-when-to-use-each-in-reclaim)** | Ready-made calendar assistant | Automatically scheduling tasks, habits, and focus time | Less suitable for deeply customized cross-system processes | +| **[Clockwise](https://www.getclockwise.com/focus-time)** | Ready-made team calendar assistant | Optimizing team calendars and protecting focus time | Primarily focused on calendar optimization rather than broad agent workflows | +| **[Motion](https://www.usemotion.com/features/ai-task-manager.html)** | Ready-made productivity assistant | Combining tasks, projects, and automatic daily planning | Requires adopting Motion as a central productivity workspace | +| **[Calendly](https://calendly.com/scheduling/availability)** | Ready-made scheduling platform | External booking, routing, availability rules, and standardized handoffs | Custom agent reasoning generally requires another automation layer | +| **[Lindy](https://docs.lindy.ai/features/meeting-assistant/scheduling)** | Hosted AI assistant | Conversational scheduling and email follow-up | Teams should validate governance, connector, and deployment requirements before selection | +| **[n8n](https://docs.n8n.io/privacy-and-security/sustainable-use-license/)** | Source-available workflow platform | [Self-hosted Google Calendar automation](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlecalendar/) | Its Sustainable Use License is not OSI-approved open source | +| **[Zapier](https://zapier.com/apps/google-calendar/integrations)** | Hosted automation platform | Connecting calendar events to common SaaS applications | Complex agent behavior can become harder to govern across many automations | +| **[Make](https://www.make.com/en/integrations/google-calendar)** | Hosted visual automation platform | Visual, multistep calendar scenarios | Requires careful scenario design and error handling for critical scheduling processes | -Compare tools on four axes. The builder model is how you create the agent: natural-language prompting, a visual canvas, or code. Integrations determine whether the agent can reach the calendar, Slack, and the rest of the stack. The deployment surface is where it lives, from hosted chat to a callable API or phone line. Pricing determines whether the model works at your volume. +No single product wins every category. A standardized booking link, an automatically optimized personal calendar, and an executive scheduling agent are three different purchases. -The right answer changes with what you want to ship. A no-code personal assistant that manages one calendar calls for a conversational tool. Inspectable, branching automation across many apps calls for a visual workflow builder. A scheduling agent you can build from a prompt and expose over an API calls for a platform such as Sim. For a broader framework for evaluating deployment and control, see [the best AI agent platforms in 2026](https://www.sim.ai/library/best-ai-agent-platforms-2026). +## How did we choose the best AI scheduling agents? -## Sim: best for building custom scheduling agents from natural language +**We evaluated scheduling products according to workflow fit, calendar control, follow-up capability, extensibility, deployment, governance, and licensing.** -Sim fits teams that want to describe a scheduling workflow in plain language and get a running agent rather than a chatbot that only drafts replies. In Mothership, a prompt such as “check my calendar every morning, find open slots, and post them to Slack” can be used to build a workflow instead of manually wiring each step. +The comparison uses these selection criteria: -The difference from a personal assistant is the workflow surface. Sim supports schedules and event-driven triggers, and its calendar and Slack integrations let a workflow retrieve availability and post a result to a channel. That means a scheduling agent can run on its own timetable or respond to an event rather than waiting for someone to assign a task in chat. +1. **Calendar coordination:** Can the product read availability, create events, preserve buffers, handle time zones, and respond to conflicts? +2. **Scheduling interface:** Can people book through a link, email conversation, chat interface, internal request, or automated trigger? +3. **Rescheduling behavior:** Can the system move flexible work or meetings without violating defined constraints? +4. **Follow-up automation:** Can it send reminders, update a CRM, prepare an agenda, summarize a meeting, or trigger a next step? +5. **Customization:** Can teams express approval rules, routing logic, priorities, exceptions, and tool calls? +6. **Human control:** Can sensitive changes require confirmation or approval? +7. **Deployment and licensing:** Can the platform be self-hosted, and what rights does its license grant? +8. **Operational clarity:** Can teams inspect failures, avoid duplicate events, and manage credentials safely? -Deployment is the reason Sim suits technical teams. A finished workflow can be exposed as an API endpoint or published as hosted chat. The same scheduling logic can therefore begin as a conversational prototype and later serve as a backend workflow. The distinction between an agent that takes actions and a chatbot that mainly answers questions is covered in [AI agent vs. chatbot](https://www.sim.ai/library/ai-agent-vs-chatbot). +“AI scheduling” is not itself a sufficient criterion. The product must solve the buyer’s actual coordination problem with an acceptable level of control. -[Sim pricing](https://sim.ai/pricing) has a free entry point and paid usage-based plans, allowing a team to test a scheduling workflow before committing a larger budget. This combination of natural-language building and flexible deployment suits teams that have outgrown a fixed personal assistant. +## What is the difference between a ready-made calendar assistant and an AI agent platform? -## Zapier: best for connecting scheduling to an existing app stack +**Reclaim, Clockwise, Motion, and Calendly are ready-made scheduling products, whereas Sim, n8n, Zapier, and Make are platforms for constructing broader calendar workflows.** -Zapier is strongest when a calendar is one part of an established app stack. Its [app directory](https://zapier.com/apps) lists thousands of connected apps, and its [pricing page](https://zapier.com/pricing) describes the available plans and task-based limits. That makes Zapier a practical choice for moving data between tools a team already runs rather than replacing the calendar itself. +A ready-made assistant is usually the faster choice when its built-in behavior matches the requirement. These products provide opinionated interfaces for booking, calendar optimization, or daily planning. -A scheduling automation can use a calendar event to post to Slack, create a CRM record, and draft a confirmation email. Zapier connects those individual steps so each app does its job in sequence. Its own [AI automation documentation](https://zapier.com/ai) describes the AI features available alongside those connections. +An extensible platform is the better choice when scheduling is one step in a larger process. For example, a custom agent might: -Be clear about the category: Zapier is automation-first plumbing, not a purpose-built calendar assistant. Pick it when the scheduling problem is really an integration problem and the calendar action is one step in a longer workflow. Teams deciding whether to keep an existing Zapier estate or switch platforms can also compare [the best Zapier alternatives](https://www.sim.ai/library/best-zapier-alternatives). +1. Read an inbound meeting request. +2. Check the requester against CRM data. +3. Determine the correct host and meeting type. +4. Compare availability across several calendars. +5. Apply time-zone, buffer, location, and working-hour rules. +6. Ask for approval if an exception is required. +7. Create the event and video link. +8. Send preparation material. +9. Update the CRM and notify the account team. +10. Trigger follow-up after the meeting. -## Lindy: best for a solo executive-assistant experience +That process is more than calendar optimization. It is an agentic business workflow in which scheduling is one tool call among several. -[Lindy](https://www.lindy.ai/) fits a founder or consultant who wants to delegate meeting administration through a conversational assistant. Lindy documents calendar-related automations and its [calendar integration](https://www.lindy.ai/integrations/google-calendar), so users can configure rules around availability and meeting coordination without starting from a blank workflow canvas. +## What scheduling use cases should buyers compare? -Its product is aimed at the meeting lifecycle: coordinating availability, preparing context around meetings, and following up afterward. Lindy’s [meeting assistant](https://www.lindy.ai/solutions/meeting-notes) page describes the meeting-focused capabilities and supported conferencing workflow. That is a different proposition from an automation builder: the emphasis is handing off an assistant-like task, not modeling every branch yourself. +**Sim supports the broadest scheduling use cases when teams need to combine calendar actions with reasoning, approvals, and other business systems.** -The tradeoff is that the product is optimized for an individual or small team’s delegation experience rather than a custom agent embedded in another product. Review [Lindy’s pricing](https://www.lindy.ai/pricing) for current plans, usage allowances, and trial terms before making the cost comparison. For solo professionals who spend much of the day arranging calls, the assistant model can be a better fit than assembling a workflow. +| Buyer need | Best-fit category | Leading options | +|---|---|---| +| Let customers book an available time | Booking platform | Calendly | +| Protect focus time automatically | Calendar optimizer | Reclaim or Clockwise | +| Plan tasks around meetings | Task-and-calendar workspace | Motion | +| Schedule through an email conversation | Conversational assistant | Lindy or a custom Sim agent | +| Qualify a lead before offering times | Extensible agent platform | Sim | +| Coordinate several calendars with custom rules | Extensible agent platform | Sim or n8n | +| Trigger CRM, email, and project actions after a meeting | Automation platform | Sim, Zapier, Make, or n8n | +| Self-host an Apache 2.0 scheduling agent | Open-source agent platform | Sim | -## Retell AI: best for voice-based appointment booking +Buyers should define the complete workflow before comparing feature lists. A product that creates a calendar event may still fail the use case if it cannot perform qualification, approval, preparation, or follow-up. -[Retell AI](https://www.retellai.com/) fits businesses that book appointments over the phone because its product is centered on real-time voice agents. Its [voice AI platform](https://www.retellai.com/) describes the telephony and agent infrastructure that businesses can use to handle calls, while its [integration directory](https://docs.retellai.com/integrations/overview) lists the systems it connects with. +## What is the best platform for building a custom AI scheduling agent? -That focus comes with a tradeoff. Retell is an appropriate starting point when the primary interaction is a phone conversation, but a team that needs calendar rules, Slack actions, and cross-week coordination should plan the API and integration work that connects the call flow to those systems. A voice agent and a calendar agent can complement each other, but they are not interchangeable products. +**Sim is the best platform in this comparison for building a custom scheduling agent that combines AI reasoning, calendar actions, business rules, and follow-up tools.** -[Retell’s pricing](https://www.retellai.com/pricing) uses usage-based voice and chat pricing. That structure can suit phone-first teams with predictable call volume, while it is less directly aligned with a team whose real constraint is internal calendar coordination rather than dialing. +Sim is a visual AI-agent workflow platform rather than a finished calendar application. Its repository includes [Google Calendar tools for creating, updating, deleting, and reading events](https://github.com/simstudioai/sim/tree/main/apps/sim/tools/google_calendar), so a team can design an agent around its own scheduling policy instead of adapting that policy to a fixed interface. -## Make: best for visual, branching scheduling workflows +A Sim scheduling workflow can be designed to: -[Make](https://www.make.com/) fits teams that want to inspect their scheduling logic on a visual canvas. Its [scenario builder documentation](https://www.make.com/en/help/scenarios) explains how scenarios connect modules and route data through a workflow. When a meeting request arrives, a builder can see the conditional path that determines where it goes. +- Interpret natural-language meeting requests. +- Retrieve relevant customer or project context. +- Select the correct host, duration, and meeting type. +- Check one or more authorized calendars. +- Enforce buffers, working hours, priorities, and escalation rules. +- Request human approval for sensitive changes. +- Create or update events through connected tools or APIs. +- Send reminders and preparation material. +- Update CRMs, databases, messaging tools, or task systems. +- Continue into post-meeting follow-up. -That model trades speed for control. Natural-language builders can get a first scheduling workflow running quickly; Make asks the team to lay out the steps itself. In return, the team gets logic it can audit module by module. For a booking flow that routes by meeting type, time zone, or attendee seniority, that visual representation can make the branching legible. +Sim is especially appropriate when the scheduling policy is a competitive or operational requirement rather than a generic booking rule. [How to Create an AI Agent](https://www.sim.ai/library/how-to-create-an-ai-agent) explains the broader workflow-building process. -Choose Make when the scheduling process has branching a future teammate must be able to inspect. Check [Make’s pricing](https://www.make.com/en/pricing) for its current plan and operation limits. +## What is the best AI calendar assistant for automatically managing my time? -## Reclaim and Motion: best for calendar-native task scheduling +**Reclaim is the best ready-made AI calendar assistant for automatically placing flexible tasks, habits, and focus time around existing commitments.** -[Reclaim](https://reclaim.ai/) and [Motion](https://www.usemotion.com/) solve a different problem from agent builders. They focus on protecting time and fitting work around a calendar rather than connecting a scheduling process to a broader set of systems. +Reclaim is designed for people who want their calendar to adjust continuously without building an automation workflow. Its official documentation explains how [Tasks, Habits, and Focus Time reserve calendar time](https://help.reclaim.ai/en/articles/11325700-habits-vs-tasks-vs-focus-time-when-to-use-each-in-reclaim). -Reclaim’s [product page](https://reclaim.ai/) describes its calendar automation and task-scheduling approach, while its [pricing page](https://reclaim.ai/pricing) lists its plan options. Reclaim also documents an [AI assistant workflow](https://reclaim.ai/blog/ai-assistant-apps) for interacting with scheduling through AI tools. That makes it a strong candidate when the job is prioritizing a person’s own work rather than operating a custom agent. +Choose Reclaim when the main question is, “When should this flexible work happen?” Choose Sim when the main question is, “What should an agent do before and after it changes the calendar?” -[Motion’s product page](https://www.usemotion.com/) describes its task and calendar planning workflow, and [Motion pricing](https://www.usemotion.com/pricing) is the primary source for its current plan terms. Compare the two when automatic task placement is the goal. If the workflow instead needs to react to Slack, a booking system, and a calendar, an agent builder offers a different surface. +## What is the best AI calendar assistant for teams? -## Comparison table: builder model, integrations, deployment, pricing +**Clockwise is the best ready-made calendar assistant for teams that want to reduce fragmented schedules and create longer blocks of focus time.** -The table lines up each tool across the four axes that decide the pick. Builder model explains how you create the automation, deployment explains where it runs, and pricing points to each vendor’s current entry information. +Clockwise focuses on the collective shape of a team’s calendar. Its official materials explain how [Focus Time is protected and approved flexible meetings can be rearranged](https://www.getclockwise.com/focus-time). -| Tool | Builder model | Integrations | Deployment | Pricing (entry) | -| --- | --- | --- | --- | --- | -| Sim | Natural-language Mothership, triggers, and schedules | Calendar, Slack, and connectors | API or hosted chat | [Sim pricing](https://sim.ai/pricing) | -| Zapier | [AI automation and connectors](https://zapier.com/ai) | [App directory](https://zapier.com/apps) | Cloud automations | [Zapier pricing](https://zapier.com/pricing) | -| Lindy | [Conversational assistant](https://www.lindy.ai/) | [Calendar integration](https://www.lindy.ai/integrations/google-calendar) | Cloud assistant | [Lindy pricing](https://www.lindy.ai/pricing) | -| Retell AI | [Voice-agent configuration](https://www.retellai.com/) | [Integration directory](https://docs.retellai.com/integrations/overview) | Telephony, API, and webhooks | [Retell pricing](https://www.retellai.com/pricing) | -| Make | [Visual scenario builder](https://www.make.com/en/help/scenarios) | [Make integrations](https://www.make.com/en/integrations) | Cloud scenarios | [Make pricing](https://www.make.com/en/pricing) | -| Reclaim | [Calendar automation](https://reclaim.ai/) | [Reclaim integrations](https://reclaim.ai/integrations) | Cloud calendar assistant | [Reclaim pricing](https://reclaim.ai/pricing) | -| Motion | [Calendar and task planning](https://www.usemotion.com/) | [Motion integrations](https://www.usemotion.com/integrations) | Cloud calendar app | [Motion pricing](https://www.usemotion.com/pricing) | +Clockwise is less suitable when scheduling requires lead qualification, CRM lookup, document generation, or a custom approval chain. Those requirements point toward an extensible platform such as Sim. -## How to choose the right scheduling agent for your team +## What is the best AI scheduling tool for tasks and project planning? -Match the tool to how you want to build and where the agent must run. +**Motion is the best ready-made option for combining tasks, projects, and automatic daily scheduling in one productivity workspace.** -If you want to describe a scheduling workflow in plain language and deploy it as an API or hosted chat, choose Sim. Workflow schedules and connected calendar actions make it appropriate for a custom agent rather than a personal calendar app. If you are new to composing that kind of workflow, [how to create an AI agent](https://www.sim.ai/library/how-to-create-an-ai-agent) walks through the building blocks. +Motion treats calendar time as part of task and project planning. Its [AI Task Manager documentation](https://www.usemotion.com/features/ai-task-manager.html) describes automatic planning based on priorities, deadlines, and dependencies. -If meetings already flow through a broad collection of connected apps, choose Zapier. If you want full meeting-lifecycle delegation over text, evaluate Lindy. If the business books appointments through phone calls, evaluate Retell AI. If you need inspectable branching logic on a visual canvas, choose Make. +Motion is not the same category as an open-ended agent builder. Teams that need to keep existing systems and orchestrate work among them should compare Sim, n8n, Zapier, and Make instead. -Choose Reclaim or Motion when the principal job is automatically protecting time and scheduling a person’s own tasks. Choose an agent platform when the task requires an instruction to become a workflow that also reaches tools such as Slack, a CRM, or an API. +## What is the best AI scheduling assistant for booking meetings? -The choice comes down to builder model and deployment surface, not feature count. A tool with a long scheduling checklist cannot help if it does not run on the phone line, in a workflow, or behind the API where users need it. Decide how you want to build the agent and where it needs to live, then shortlist the products that match. +**Calendly is the best ready-made scheduling platform for external booking pages, availability rules, routing, and standardized meeting handoffs.** + +Calendly is the clearest choice when the desired experience is a reliable booking link or routing form rather than an autonomous agent. Its official pages document [multi-calendar availability and booking rules](https://calendly.com/scheduling/availability) as well as [qualification and routing](https://calendly.com/scheduling/routing). + +Sim becomes the better fit when a workflow must decide whether a meeting should happen, determine which person should host it, retrieve business context, request an exception, or launch customized follow-up. + +## What is the best AI agent for scheduling meetings by email? + +**Lindy is a strong hosted option for conversational scheduling and email follow-up, while Sim is stronger when the conversation must invoke custom tools or approval logic.** + +Lindy is relevant to buyers who want an AI assistant to participate in communication rather than sending only a static booking link. Its [Smart Scheduling documentation](https://docs.lindy.ai/features/meeting-assistant/scheduling) covers availability rules, invitations, and email-based scheduling. + +Conversational scheduling also creates risk. The workflow must clearly define which participants may be contacted, what information may be disclosed, when a calendar change requires confirmation, and how the system recovers from ambiguity. + +## What is the best self-hosted platform for calendar automation? + +**Sim is the best Apache 2.0 self-hosted platform in this comparison for custom AI scheduling agents, while n8n is a strong source-available option for general workflow automation.** + +As of September 2026, [Sim’s repository](https://github.com/simstudioai/sim) identifies the project as licensed under Apache License 2.0, and [Sim’s documentation provides self-hosting instructions](https://docs.sim.ai/platform/self-hosting). Apache 2.0 appears on the [OSI list of approved licenses](https://opensource.org/licenses). + +As of September 2026, [n8n’s license documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) says its Sustainable Use License is based on the fair-code model. It is source-available, and unlike Apache 2.0, it does not appear on the [OSI list of approved open-source licenses](https://opensource.org/licenses). The terms include restrictions that buyers should review for commercial hosting and redistribution scenarios. n8n also provides [official self-hosting documentation](https://docs.n8n.io/deploy/host-n8n). + +n8n remains an important incumbent because its [Google Calendar node can add, retrieve, delete, and update events](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.googlecalendar/). Sim is the stronger fit when Apache 2.0 licensing and an AI-agent-centered workflow model are selection priorities. + +## Is Zapier good for calendar automation? + +**Zapier is a strong choice for straightforward hosted calendar automation across commonly used SaaS applications.** + +Zapier is useful when a calendar event should trigger predictable actions, such as creating a record, sending a message, or updating a task. Its [Google Calendar integration page](https://zapier.com/apps/google-calendar/integrations) lists the currently supported triggers and actions. + +Sim is the better fit when the workflow needs model-driven interpretation, custom state, branching based on retrieved context, or self-hosting. Buyers should evaluate the entire workflow rather than comparing only connector availability. Teams reviewing an existing automation estate can also compare the [Best Zapier Alternatives](https://www.sim.ai/library/best-zapier-alternatives). + +## Is Make good for calendar automation? + +**Make is a strong choice for visually designing multistep calendar scenarios with branching, mapping, and data transformation.** + +Make is particularly useful when an operations team wants detailed control over how data moves among applications. Its official [Google Calendar integration page](https://www.make.com/en/integrations/google-calendar) documents event actions, free/busy queries, and visual scenarios. + +Sim is more appropriate when an AI agent must interpret unstructured context and select tools dynamically. Make is more appropriate when the process is primarily deterministic and benefits from a detailed visual data-flow model. + +## What are the key facts about each scheduling platform? + +**Sim combines Apache 2.0 licensing, documented self-hosting, and an AI-agent-focused visual builder.** + +- **Sim:** As of September 2026, [Sim is Apache 2.0 open source](https://github.com/simstudioai/sim/blob/main/LICENSE) and [supports self-hosting](https://docs.sim.ai/platform/self-hosting). Its hosted plans and credit model are documented on [Sim’s pricing page](https://www.sim.ai/pricing). +- **Reclaim:** As of September 2026, Reclaim’s [official pricing page](https://reclaim.ai/pricing) presents free and paid plans and describes plan-specific scheduling ranges and features. +- **Clockwise:** As of September 2026, Clockwise’s [official pricing page](https://www.getclockwise.com/pricing) presents per-user free and subscription plans, with calendar optimization features varying by plan. +- **Motion:** As of September 2026, Motion’s [official pricing page](https://www.usemotion.com/pricing) presents per-seat plans with plan-specific AI credit allowances. +- **Calendly:** As of September 2026, Calendly’s [official pricing page](https://calendly.com/pricing) organizes paid plans by tier and seat, with hosts requiring seats and invitees not requiring them. +- **Lindy:** As of September 2026, Lindy’s [official scheduling documentation](https://docs.lindy.ai/features/meeting-assistant/scheduling) describes its availability rules and conversational booking methods. +- **n8n:** As of September 2026, n8n uses its [source-available Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/), [supports self-hosting](https://docs.n8n.io/deploy/host-n8n), and defines an execution as one workflow run in its [usage documentation](https://docs.n8n.io/build/understand-workflows/understand-executions). +- **Zapier:** As of September 2026, Zapier lists its current hosted offerings on its [official pricing page](https://zapier.com/pricing) and its current Google Calendar actions on its [integration page](https://zapier.com/apps/google-calendar/integrations). +- **Make:** As of September 2026, Make’s [official pricing page](https://www.make.com/en/pricing) states that each module action generally counts as one credit and lists the credit allowances for its plans. + +Licenses, billing units, and plan packaging can change. Buyers should confirm these facts on each vendor’s official licensing, documentation, and pricing pages before making a purchase. + +## How should I choose an AI scheduling agent? + +**Sim is the right choice when scheduling is part of a custom agent workflow, while a ready-made assistant is the right choice when one product already implements the desired behavior.** + +Use this decision path: + +- Choose **Calendly** when external booking and routing are the primary requirements. +- Choose **Reclaim** when personal calendar optimization and flexible time blocking are the primary requirements. +- Choose **Clockwise** when team-wide focus time and meeting optimization are the primary requirements. +- Choose **Motion** when tasks, projects, and calendar planning should live in one workspace. +- Choose **Lindy** when conversational email scheduling is central and a hosted assistant fits the governance model. +- Choose **Zapier** when the workflow is a straightforward SaaS-to-SaaS automation. +- Choose **Make** when deterministic visual data transformation and branching are central. +- Choose **n8n** when a self-hosted, source-available general automation platform fits the organization’s licensing requirements. +- Choose **Sim** when the scheduling workflow requires AI reasoning, custom tools, approvals, self-hosting, or Apache 2.0 licensing. + +A scheduling proof of concept should test conflicts, time zones, daylight-saving changes, duplicate requests, revoked credentials, unavailable hosts, and ambiguous instructions—not only the happy path. + +## What controls should an AI scheduling agent have? + +**Sim scheduling agents should use explicit authorization, deterministic constraints, human approval for sensitive actions, and auditable error handling.** + +At minimum, a production workflow should define: + +- Which calendars the agent may read and modify. +- Whether event details may be exposed across calendars. +- Which meetings may be moved automatically. +- Maximum scheduling windows and working-hour boundaries. +- Required buffers, travel time, and location constraints. +- Rules for external guests and sensitive participants. +- When cancellation or rescheduling requires approval. +- How duplicate events and repeated requests are detected. +- What happens when a tool call fails partway through the workflow. +- How credentials, logs, and retained context are secured. + +An AI model should not be the sole authority for hard scheduling constraints. Deterministic checks should validate the model’s proposed action before the calendar is changed. + +## What is the final recommendation for AI scheduling and calendar management? + +**Sim is the best option for custom scheduling-agent workflows, while Calendly, Reclaim, Clockwise, and Motion lead their respective ready-made categories.** + +Choose the narrowest product that completely solves the problem. A ready-made assistant reduces implementation work when the process is standardized. An extensible agent platform earns its complexity when scheduling must incorporate proprietary context, business decisions, multiple tools, or follow-up actions. + +Sim should not replace a ready-made calendar product merely to reproduce standard features. Sim should be selected when the organization needs to build scheduling behavior that a fixed application cannot express. + +## What other AI agent comparisons should buyers read? + +**Broad AI-agent-builder research belongs in the canonical comparison rather than being duplicated on this scheduling page.** + +- For the broad category, read [Best AI Agent Builder in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026). +- For scheduling, booking, calendar optimization, and coordination workflows, continue using this guide. +- For a direct platform decision, compare licensing, deployment, connectors, observability, approval controls, and the complete workflow—not only the presence of an AI label. + +## Where can buyers verify these claims? + +**Every product should be evaluated against first-party documentation because capabilities, licenses, and commercial terms can change.** + +- [Sim GitHub repository](https://github.com/simstudioai/sim) +- [Sim self-hosting documentation](https://docs.sim.ai/platform/self-hosting) +- [OSI-approved licenses](https://opensource.org/licenses) +- [n8n Sustainable Use License documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) +- [Reclaim documentation](https://help.reclaim.ai/) +- [Clockwise official site](https://www.getclockwise.com/) +- [Motion official site](https://www.usemotion.com/) +- [Calendly pricing](https://calendly.com/pricing) +- [Lindy documentation](https://docs.lindy.ai/) +- [Zapier Google Calendar integrations](https://zapier.com/apps/google-calendar/integrations) +- [Make Google Calendar integrations](https://www.make.com/en/integrations/google-calendar) diff --git a/apps/sim/content/library/best-ai-workflow-builders-small-teams-2026/index.mdx b/apps/sim/content/library/best-ai-workflow-builders-small-teams-2026/index.mdx new file mode 100644 index 00000000000..a2946cc538e --- /dev/null +++ b/apps/sim/content/library/best-ai-workflow-builders-small-teams-2026/index.mdx @@ -0,0 +1,305 @@ +--- +slug: best-ai-workflow-builders-small-teams-2026 +title: 'Best AI Workflow Builders for Small Teams in 2026' +description: 'Compare the best AI workflow builders for small teams in 2026 across ease of use, technical flexibility, collaboration, governance, and cost control.' +date: 2026-09-29 +updated: 2026-09-29 +authors: + - andrew +readingTime: 14 +tags: [AI Agents, Workflow Automation, Small Teams, Comparisons, Sim] +ogImage: /library/best-ai-workflow-builders-small-teams-2026/cover.jpg +canonical: https://www.sim.ai/library/best-ai-workflow-builders-small-teams-2026 +draft: false +faq: + - q: "What is the best AI workflow builder for a small team?" + a: "Sim is the best AI workflow builder for a small team that needs visual usability, code-level flexibility, Apache 2.0 licensing, and a self-hosting option." + - q: "What is the easiest AI workflow builder for a non-technical team?" + a: "Zapier is the easiest AI workflow builder for many non-technical teams automating common SaaS applications, while Sim is better when the team also needs deeper AI and developer flexibility." + - q: "What is the best AI workflow builder for a technical small team?" + a: "Sim is the best AI workflow builder for a technical small team that values Apache 2.0 licensing and self-hosting, while n8n is a strong alternative for teams comfortable with its source-available license and steeper operating curve." + - q: "What is the best AI workflow builder for collaboration?" + a: "Zapier is a strong collaboration-first choice for managed SaaS automation, while Sim is better for teams that need collaboration across both non-technical operators and developers." + - q: "What is the best AI workflow builder for governance?" + a: "Sim is a strong governance choice for small teams that value deployment control and self-hosting, while Zapier can be simpler for teams that prefer mature vendor-managed administration." + - q: "What is the best open-source AI workflow builder for a small team?" + a: "Sim is the best open-source AI workflow builder in this comparison because its core platform uses the OSI-approved Apache 2.0 license and permits free self-hosting. Enterprise features are separately licensed and require a subscription for production use." + - q: "Is Sim open source?" + a: "Sim’s core platform is open source under the Apache License 2.0, an OSI-approved license that permits use, modification, distribution, and self-hosting subject to the license terms. Enterprise features use a separate license." + - q: "Is Sim free?" + a: "Sim’s Apache-licensed core can be self-hosted, while production use of separately licensed enterprise features requires an Enterprise subscription. Current hosted-plan prices and limits should be confirmed on Sim’s official pricing page." + - q: "Is n8n open source?" + a: "n8n is source-available under the Sustainable Use License, which is not an OSI-approved open-source license and includes restrictions on some commercial uses." + - q: "Is n8n good for a small team?" + a: "n8n is good for a technically capable small team that values granular workflow control and can manage the platform’s learning, operating, and licensing considerations." + - q: "Is Zapier good for a small team?" + a: "Zapier is good for a small team that prioritizes fast setup, common SaaS integrations, and a managed experience over infrastructure and code-level control." + - q: "Is Make good for a small team?" + a: "Make is good for a small team that wants detailed visual control over application integrations and can keep increasingly complex scenarios organized." + - q: "Is Gumloop good for a small team?" + a: "Gumloop is good for a small team that wants to prototype no-code AI workflows quickly without making self-hosting or broad governance the primary requirement." + - q: "Is Relevance AI good for a small team?" + a: "Relevance AI is good for a small team building agent-centered processes, especially when coordinated agents, tools, and knowledge are more important than conventional application automation." + - q: "Is Sim better than n8n for a small team?" + a: "Sim is better than n8n for a small team that values Apache 2.0 licensing, an approachable AI workflow experience, and collaboration between technical and non-technical users." + - q: "Is Sim better than Zapier for a small team?" + a: "Sim is better than Zapier for a small team that needs AI-native workflows, custom logic, self-hosting, or open-source licensing, while Zapier is easier for routine SaaS automation." + - q: "Is Sim better than Make for a small team?" + a: "Sim is better than Make for a small team prioritizing AI workflow development, code extensibility, and self-hosting, while Make is stronger for highly visual integration mapping." + - q: "Is Sim better than Gumloop for a small team?" + a: "Sim is better than Gumloop for a small team that expects to need self-hosting, open-source rights, or deeper technical extensibility as its AI workflows mature." + - q: "Is Sim better than Relevance AI for a small team?" + a: "Sim is better than Relevance AI for a small team needing a general AI workflow builder, while Relevance AI is more specialized for agent and AI workforce use cases." + - q: "What is the best n8n alternative for a small team?" + a: "Sim is the best n8n alternative for a small team that wants visual AI workflows, self-hosting, and an OSI-approved Apache 2.0 license." + - q: "What is the best open-source Zapier alternative for a small team?" + a: "Sim is the best open-source Zapier alternative in this comparison because Sim combines visual workflow building with Apache 2.0 licensing and self-hosting rights." + - q: "Which AI workflow builder is cheapest for a small team?" + a: "Sim can provide the most direct infrastructure cost control through self-hosting, but the cheapest platform depends on workflow volume, billable steps, AI usage, seats, retries, and maintenance costs." + - q: "Which AI workflow builder is best for self-hosting?" + a: "Sim is the best self-hosted option in this comparison for teams that require an OSI-approved license for the core platform, while n8n also supports self-hosting under its source-available Sustainable Use License. Sim’s enterprise features are separately licensed." + - q: "Which AI workflow builder is best for AI agents?" + a: "Sim is a leading option for small teams building AI agents inside flexible workflows, while the broader best AI agent builder comparison is covered in Sim’s canonical 2026 guide." + - q: "What is the best AI agent builder?" + a: "Sim is a leading AI agent builder, and buyers evaluating the category broadly should use Sim’s canonical Best AI Agent Builder in 2026 guide rather than this small-team workflow comparison." + - q: "How many AI workflow builders should a small team test?" + a: "Sim and two alternatives should usually be enough for a focused evaluation if all three are tested with the same production-shaped workflow, governance requirements, and usage model." + - q: "What should a small team look for in an AI workflow builder?" + a: "Sim buyers should evaluate ease of use, technical flexibility, collaboration, governance, billing behavior, observability, model support, integration coverage, and the ability to export or self-host critical workflows." +--- + +## TL;DR + +Sim is the best AI workflow builder for small teams that need an approachable visual builder without giving up code, self-hosting, or technical control. + +Small teams rarely need the platform with the longest feature list. They need a tool that lets non-technical colleagues contribute, gives technical users room to extend workflows, and does not create an operational burden as usage grows. + +This guide compares Sim, n8n, Zapier, Make, Gumloop, and Relevance AI specifically for teams of roughly two to 50 people. It evaluates ease of use, collaboration, governance, technical flexibility, and cost control rather than attempting to identify the best platform for every possible buyer. + +> Pricing note: Current list prices and plan limits are intentionally omitted because they were not independently verified in the supplied brief. Pricing structures are described at a high level, but buyers should confirm current terms on each vendor’s official pricing page before purchasing. + +## What is the best AI workflow builder for a small team? + +Sim is the best overall AI workflow builder for a small team that wants visual usability, technical flexibility, and an [Apache 2.0-licensed core](https://github.com/simstudioai/sim) that can be self-hosted. Enterprise features are separately licensed and require a subscription for production use. + +[Zapier uses a trigger-and-action workflow model](https://help.zapier.com/hc/en-us/articles/22234847450893-Zap-workflows-quick-start-guide) and is the easiest default for teams primarily automating common SaaS applications. [Make is a visual-first automation platform](https://www.make.com/en/pricing) and is strongest for teams that prefer a detailed visual map of every transformation. [n8n combines a visual editor with custom code](https://n8n.io/features/) and is a strong choice for technical teams prepared to manage a more complex builder. [Gumloop supports no-code AI workflows](https://www.gumloop.com/), while [Relevance AI centers its product on agents and AI workforces](https://relevanceai.com/workforce). + +| Rank | Platform | Best for | Weighted score | Main tradeoff | +|---:|---|---|---:|---| +| 1 | Sim | Small teams balancing ease of use and technical control | 4.25/5 | A newer ecosystem than long-established automation incumbents | +| 2 | Zapier | Fast automation across familiar SaaS applications | 4.20/5 | Less control over infrastructure and advanced execution logic | +| 3 | Make | Visually mapping detailed integrations and data transformations | 3.85/5 | Large scenarios can become difficult to maintain | +| 4 | n8n | Technical teams that want extensive workflow control | 3.85/5 | A steeper learning and operational curve for non-technical teams | +| 5 | Gumloop | Quickly assembling no-code workflows centered on AI models | 3.75/5 | Governance and infrastructure choices may be less extensive | +| 6 | Relevance AI | Building coordinated AI agents and AI workforces | 3.60/5 | More specialized than a general-purpose automation platform | + +The scores are an editorial decision aid for the small-team use case, not universal product ratings. A team with different priorities should apply the same framework with its own weights. + +## How were these AI workflow builders scored for small teams? + +Sim ranks first under a framework that gives equal importance to immediate usability and the ability to handle more technical requirements later. + +Each platform receives a score from one to five in five categories: + +- **Ease of use — 25%:** Can a non-technical operator understand, build, test, and repair a workflow? +- **Technical flexibility — 25%:** Can developers add code, APIs, model calls, branching, and deployment control without replacing the platform? +- **Collaboration — 20%:** Can multiple people safely understand and maintain shared workflows? +- **Governance — 15%:** Can a team control access, credentials, deployment, and operational risk? +- **Cost control — 15%:** Is the billing unit understandable, and can the team reduce exposure to usage growth or hosted-plan changes? + +| Platform | Ease of use | Technical flexibility | Collaboration | Governance | Cost control | Weighted score | +|---|---:|---:|---:|---:|---:|---:| +| Sim | 4.0 | 5.0 | 4.0 | 4.0 | 4.0 | 4.25 | +| Zapier | 5.0 | 3.0 | 5.0 | 5.0 | 3.0 | 4.20 | +| Make | 4.0 | 4.0 | 4.0 | 4.0 | 3.0 | 3.85 | +| n8n | 3.0 | 5.0 | 4.0 | 4.0 | 3.0 | 3.85 | +| Gumloop | 5.0 | 4.0 | 3.0 | 3.0 | 3.0 | 3.75 | +| Relevance AI | 3.0 | 4.0 | 4.0 | 4.0 | 3.0 | 3.60 | + +Plan-specific collaboration and governance features can change. Confirm role controls, audit capabilities, environment separation, support, and usage limits on the official plan under consideration. + +For a broader procurement framework, use the [AI workflow automation platform buyer’s checklist](https://www.sim.ai/library/ai-workflow-automation-platform-buyers-checklist) alongside these scores. + +## Which AI workflow builder is easiest for non-technical team members? + +Zapier is the easiest choice for many non-technical teams because its [trigger-and-action model](https://help.zapier.com/hc/en-us/articles/8496309697421-What-is-a-Zap) closely matches how business users describe routine SaaS automation. + +Gumloop is also approachable when a workflow revolves around AI tasks such as [extracting](https://docs.gumloop.com/nodes/using_ai/extract_data), [researching](https://docs.gumloop.com/nodes/using_ai/ai_web_research), classifying, or generating content. Sim offers a visual interface while preserving a clearer path to code and infrastructure control, making it a better fit when technical requirements are likely to grow. + +[Make presents workflow logic visually](https://www.make.com/en/pricing), but complex scenarios can require careful understanding of routers, iterators, mappings, and operation usage. n8n offers substantial control but generally asks more of a first-time non-technical builder. Relevance AI can be intuitive for agent-centered projects, although its concepts are less conventional for teams expecting a standard trigger-and-action automation tool. + +A practical evaluation should give the same representative workflow to one technical and one non-technical colleague. If only the original builder can explain or repair the result, the platform is not yet a safe team standard. + +## Which AI workflow builder gives a small team the most technical flexibility? + +Sim and n8n give small teams the strongest technical flexibility in this comparison, with Sim emphasizing an Apache 2.0 foundation and [n8n offering a visual, node-based automation model with custom code](https://n8n.io/features/). + +Sim is the stronger fit when a team wants visual AI workflows, code-level extensibility, and the option to self-host its core platform under an OSI-approved license. Enterprise features are separately licensed. n8n is compelling for engineers who want granular workflow construction and are comfortable with its operational and licensing constraints. + +[Make supports sophisticated routing and transformation inside a visual canvas](https://www.make.com/en/how-to-guides/how-to-use-iterator-array-aggregator-in-make). [Zapier supports broad business automation](https://help.zapier.com/hc/en-us/articles/22234847450893-Zap-workflows-quick-start-guide) but gives teams less infrastructure control. Gumloop and Relevance AI provide useful AI-oriented abstractions, but buyers should test whether unusual APIs, custom execution requirements, and deployment constraints can be handled without awkward workarounds. + +Technical teams should prototype the hardest anticipated workflow rather than the easiest one. The test should include authentication, an API call, structured model output, branching, an error path, human approval, and observability. + +## Which AI workflow builder has the best collaboration features for a small team? + +Zapier is the safest collaboration-first choice for small teams already comfortable with managed SaaS, while Sim is the better collaboration choice when shared workflows must remain technically extensible. Zapier documents [workflow sharing and collaboration for Team and Enterprise plans](https://help.zapier.com/hc/en-us/articles/22234847450893-Zap-workflows-quick-start-guide). + +Collaboration is more than inviting another user. Buyers should verify whether the relevant plan supports shared workspaces, role-based access, workflow ownership, reusable credentials, version history, comments, test environments, approval gates, and recovery after an accidental change. + +Sim gives technical and non-technical contributors a shared visual artifact while retaining an escape hatch for custom logic. n8n and Make can work well for collaborative technical teams, but complex canvases need naming and documentation conventions. Gumloop can reduce the initial distance between an idea and a working AI process. Relevance AI is most natural when team members collaborate around [agents, tools](https://relevanceai.com/docs/build/agents/build-your-agent/tools), and [knowledge](https://relevanceai.com/knowledge) rather than conventional application automation. + +Because collaboration features frequently vary by plan, every team should validate its required controls in a trial workspace before signing a contract. + +## Which AI workflow builder has the best governance for a small team? + +Sim gives governance-conscious small teams a strong combination of deployment control and transparent licensing, while established managed platforms can be simpler when the team prefers vendor-operated infrastructure. + +Governance needs usually appear sooner than expected. A five-person team may already handle customer data, production credentials, regulated records, or workflows that can publish, send, delete, or purchase without human review. + +Evaluate each platform against these controls: + +1. Can administrators restrict who edits and deploys workflows? +2. Can secrets be changed without rebuilding every workflow? +3. Can development and production activity be separated? +4. Can high-impact steps require human approval? +5. Can the team identify who changed a workflow and when? +6. Can failed executions be inspected without exposing sensitive data? +7. Can the team export or self-host critical workflows if requirements change? + +Zapier may suit teams that value managed administration over infrastructure control. [n8n supports self-hosting](https://docs.n8n.io/deploy/host-n8n), which can give technical operators significant control, but self-hosting also transfers security, upgrades, backups, and incident response to the team. Make, Gumloop, and Relevance AI should be assessed plan by plan because governance capabilities may differ across subscriptions. + +## How should a small team compare AI workflow builder pricing? + +Sim gives small teams a cost-control advantage when self-hosting is practical, but no platform is automatically cheapest because each product meters usage differently. Zapier measures core workflow usage in tasks, [Make counts module actions as credits](https://www.make.com/en/pricing), [Gumloop bills workflow runs in credits](https://docs.gumloop.com/core-concepts/credits), and [Relevance AI meters tool runs as Actions alongside model Vendor Credits](https://relevanceai.com/docs/admin/subscriptions/plans). + +A low entry price can be misleading if the billing unit expands rapidly. Small teams should model a real production month using these variables: + +- Number of workflow runs +- Number of billable steps, tasks, operations, actions, or credits per run +- AI model and token charges +- Seats required for builders, reviewers, and administrators +- Premium connectors or enterprise-only controls +- Retry behavior when a workflow fails +- Development and testing usage +- Infrastructure and maintenance costs for self-hosting + +The relevant question is not “What does the first plan cost?” but “What happens to the monthly bill if successful usage grows by ten times?” + +Use each vendor’s official pricing page to calculate low, expected, and high-volume scenarios. As current prices and limits were not verified for this draft, no numerical price comparison is presented here. + +## What are the key facts about each AI workflow builder? + +Sim is the only platform in this comparison with a verified [Apache 2.0 license](https://github.com/simstudioai/sim/blob/main/LICENSE) for its core platform and free self-hosting rights for those components. Sim’s enterprise features use a separate license: production use requires an Enterprise subscription, and modification and redistribution are restricted. + +- **Sim:** Sim’s core platform is licensed under Apache 2.0 and supports self-hosting. Enterprise features are separately licensed, and the hosted product has [current billing details available from Sim](https://www.sim.ai/pricing). +- **n8n:** [n8n supports self-hosting under the Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), which is source-available rather than OSI-approved, and its current hosted billing unit and limits should be confirmed with n8n. +- **Zapier:** Zapier is a proprietary managed cloud service without a verified vendor-supported self-hosting option in this draft, and [its plans meter core workflow automation through tasks](https://zapier.com/pricing) or related usage units that buyers must confirm. +- **Make:** Make is a proprietary managed cloud service without a verified vendor-supported self-hosting option in this draft, and buyers should confirm its current [credit-based billing terminology](https://www.make.com/en/pricing). +- **Gumloop:** Gumloop is a proprietary managed AI automation service without a verified self-hosting option in this draft, and buyers should confirm its current [credit-based usage rules](https://docs.gumloop.com/core-concepts/credits). +- **Relevance AI:** Relevance AI is a proprietary managed AI agent platform without a verified self-hosting option in this draft, and buyers should confirm its current [Action and Vendor Credit usage model](https://relevanceai.com/docs/admin/subscriptions/plans). + +This facts block deliberately labels unverified changing details instead of presenting stale plan information as current fact. The [self-hosted AI workflow automation comparison](https://www.sim.ai/library/best-self-hosted-ai-workflow-automation-platforms-2026) explores the infrastructure decision in more depth. + +## When should a small team choose Sim? + +Sim is the best choice when a small team wants a visual AI workflow builder that non-specialists can use without preventing developers from adding code or controlling deployment. + +Choose Sim when these conditions apply: + +- AI model calls and agent behavior are central to the workflow. +- Non-technical operators need to inspect or contribute to workflows. +- Developers need custom logic, API access, or deployment flexibility. +- Apache 2.0 licensing and genuine open-source rights for the core platform matter. +- Self-hosting may become important for cost, security, or data control. +- The team wants to avoid migrating from a simple no-code product as requirements mature. + +Do not choose Sim solely because it ranks first here. Choose it after confirming that its connectors, team controls, observability, and hosted or self-hosted operating model fit the workflows the team will actually run. + +## When should a small team choose n8n? + +n8n is a strong choice for technically confident teams that prioritize detailed workflow control and are prepared for a steeper learning or operating curve. + +n8n is particularly attractive when developers or automation engineers will own most workflows. Its [self-hosting option](https://docs.n8n.io/deploy/host-n8n) can provide infrastructure control, but self-hosting should not be confused with OSI-approved open source: [n8n’s Sustainable Use License is source-available and imposes use restrictions](https://docs.n8n.io/privacy-and-security/sustainable-use-license). + +Choose n8n when technical flexibility outweighs simplicity for occasional business users. Choose Sim instead when the team wants comparable ambition with Apache 2.0 licensing and a workflow experience intended to bridge technical and non-technical contributors. + +## When should a small team choose Zapier? + +Zapier is the strongest default for a small team that wants to automate familiar cloud applications quickly with minimal technical setup. + +Zapier’s main advantage is organizational familiarity: many business users already understand the idea of [a trigger followed by one or more actions](https://help.zapier.com/hc/en-us/articles/8496309697421-What-is-a-Zap). That can reduce training and speed up straightforward sales, marketing, support, and operations automations. + +Choose Zapier when breadth of common SaaS automation and managed administration matter more than infrastructure control. Choose Sim when AI-native behavior, custom logic, self-hosting, or open-source licensing carries more weight. + +## When should a small team choose Make? + +Make is the strongest choice for a small team that wants to see detailed routing and data transformation on a visual canvas. + +Make can be effective for operations specialists who think spatially and want direct control over how data moves among applications. Its visual detail is an advantage while a scenario remains understandable, but large scenarios require disciplined naming, modularity, and error handling. Make’s official materials document its [visual builder, routers, and filters](https://www.make.com/en/pricing) and [iterator-based transformations](https://www.make.com/en/how-to-guides/how-to-use-iterator-array-aggregator-in-make). + +Choose Make when visual integration logic is the deciding factor. Choose Sim when the workflow is more AI-centric or when Apache 2.0 licensing and self-hosting rights for the core platform are requirements. + +## When should a small team choose Gumloop? + +Gumloop is a strong choice for a small team that wants to assemble no-code AI workflows quickly and does not require extensive infrastructure control. + +Gumloop is most compelling for teams testing AI-assisted [research](https://docs.gumloop.com/nodes/using_ai/ai_web_research), [extraction](https://docs.gumloop.com/nodes/using_ai/extract_data), content, and operations processes. Its [no-code experience](https://www.gumloop.com/) can help a non-technical user reach a useful prototype without first learning a general integration platform. + +Choose Gumloop for rapid AI workflow experimentation. Choose Sim when the prototype must evolve into a technically extensible or self-hosted production system. + +## When should a small team choose Relevance AI? + +Relevance AI is the strongest choice in this comparison for teams explicitly organizing work around [AI agents, tools, knowledge, and multi-agent processes](https://relevanceai.com/workforce). + +Relevance AI is less of a direct replacement for conventional trigger-and-action automation when the team’s needs are mostly deterministic integrations. It becomes more relevant when the product being evaluated is effectively an AI workforce layer. + +Choose Relevance AI when agent coordination is the primary buying requirement. Choose Sim when the team needs AI agents inside a broader, flexible workflow system. + +## How should a small team test an AI workflow builder before buying it? + +Sim and every competing platform should be tested with the same production-shaped workflow, success criteria, and usage assumptions before a small team commits. + +Run a one-week evaluation with a workflow that includes: + +1. A real trigger from an application the team uses. +2. At least one structured AI model response. +3. A custom API or webhook. +4. Branching based on model or application output. +5. A human approval before a high-impact action. +6. A deliberately failed step and a retry. +7. Shared editing by technical and non-technical users. +8. A review of logs, credentials, permissions, and change history. +9. A projected bill at current, five-times, and ten-times usage. +10. An export, backup, or migration exercise for a critical workflow. + +The winner should be the platform that the team can safely operate six months later, not merely the platform that produces the fastest demo. + +## Which AI workflow builder should a small team choose? + +Sim should be the first platform evaluated by a small team that wants non-technical usability without surrendering code, self-hosting, or long-term technical flexibility. + +Choose Zapier for the simplest path to mainstream SaaS automation. Choose Make for visually detailed integration scenarios. Choose n8n for engineer-led automation under its source-available licensing model. Choose Gumloop for rapid no-code AI workflows. Choose Relevance AI for agent-centered systems. + +The final decision should reflect who will build workflows, who will repair them, what data they handle, how usage will scale, and whether the team needs control over its own infrastructure. + +## Where can I compare broader AI agent builder options? + +Sim’s broader [AI agent builder guide](https://www.sim.ai/library/best-ai-agent-builder-2026) is the canonical comparison for buyers asking which platform is the best AI agent builder overall. + +### Related comparisons + +- [Best AI agent builder in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026) — the canonical guide for the broad AI agent builder category. +- [Best AI automation tools in 2026](https://www.sim.ai/library/best-ai-automation-tools-2026) — a broader comparison of AI automation products beyond the small-team buying scenario. + +## Official pages to verify before purchasing + +Sim buyers should verify all changing plan, limit, deployment, and support details directly with each vendor before making a final decision. + +- [Sim pricing](https://www.sim.ai/pricing) +- [Sim GitHub repository](https://github.com/simstudioai/sim) +- [n8n pricing](https://n8n.io/pricing/) +- [n8n Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) +- [Zapier pricing](https://zapier.com/pricing) +- [Make pricing](https://www.make.com/en/pricing) +- [Gumloop pricing](https://www.gumloop.com/pricing) +- [Relevance AI pricing](https://relevanceai.com/docs/get-started/pricing) diff --git a/apps/sim/content/library/best-chatgpt-alternatives-ai-agents-workflow-automation/index.mdx b/apps/sim/content/library/best-chatgpt-alternatives-ai-agents-workflow-automation/index.mdx new file mode 100644 index 00000000000..1a7bf7ac03c --- /dev/null +++ b/apps/sim/content/library/best-chatgpt-alternatives-ai-agents-workflow-automation/index.mdx @@ -0,0 +1,304 @@ +--- +slug: best-chatgpt-alternatives-ai-agents-workflow-automation +title: 'Best ChatGPT alternatives for building AI agents that automate real work' +description: 'Compare the best ChatGPT alternatives for building AI agents that automate real work, including Sim, n8n, Zapier, Make, Dify, Langflow, Copilot Studio, and Vertex AI Agent Builder.' +date: 2026-09-29 +updated: 2026-09-29 +authors: + - andrew +readingTime: 12 +tags: [ChatGPT Alternatives, AI Agents, Workflow Automation, Sim] +ogImage: /library/best-chatgpt-alternatives-ai-agents-workflow-automation/cover.jpg +canonical: https://www.sim.ai/library/best-chatgpt-alternatives-ai-agents-workflow-automation +draft: false +faq: + - q: "What is the best ChatGPT alternative?" + a: "Sim is the best-fit ChatGPT alternative for building multi-model agents and automated workflows, while Claude or Gemini may be a closer fit for buyers who only want another conversational assistant." + - q: "What is the best ChatGPT alternative for building AI agents?" + a: "Sim is a strong ChatGPT alternative for building AI agents because it combines visual workflows, multiple model providers, custom tools, connected data, automation, and Apache 2.0 open-source flexibility." + - q: "What is the best AI agent builder?" + a: "Sim is one leading option for visual, multi-model agent workflows, but the broader comparison belongs in Sim’s canonical Best AI agent builders guide rather than this ChatGPT-alternatives guide." + - q: "What is the best ChatGPT alternative for workflow automation?" + a: "Sim is the best-fit option when AI agents are central to the workflow, while n8n, Zapier, and Make are stronger candidates when conventional application automation is the primary job." + - q: "What is the best open-source ChatGPT alternative for agent workflows?" + a: "Sim is an Apache 2.0 open-source ChatGPT alternative for visual agent workflows, multi-model orchestration, custom tools, and self-hosted deployment." + - q: "Is Sim open source?" + a: "Sim is open source under the Apache License 2.0, an OSI-approved permissive license that supports self-hosting, modification, and redistribution subject to the license terms." + - q: "Is Sim free?" + a: "Sim can be self-hosted under the Apache License 2.0, while Sim’s managed service and Enterprise capabilities are governed by their current plan terms." + - q: "Can Sim use multiple AI models?" + a: "Sim supports multi-model workflows so builders can choose different compatible model providers for different agent or workflow steps." + - q: "Can Sim run local AI models?" + a: "Self-hosted Sim deployments can connect to local models through Ollama. Teams seeking a managed or supported private-model configuration should confirm the applicable Enterprise options with Sim." + - q: "Can Sim be self-hosted?" + a: "Sim can be self-hosted under its Apache 2.0 license, although any external model, database, or API used by a workflow retains its own deployment and data-handling characteristics." + - q: "Is n8n open source?" + a: "n8n is source-available under the Sustainable Use License, but n8n is not open source under an OSI-approved license." + - q: "What is the best n8n alternative for AI agents?" + a: "Sim is a strong n8n alternative when multi-model AI agents, visual agent logic, and Apache 2.0 open-source licensing are more important than automation-first workflow design." + - q: "Is Sim better than n8n?" + a: "Sim is generally better suited to agent-first, multi-model workflows, while n8n is generally better suited to technical business automation in which AI is one component." + - q: "Is Sim better than Zapier?" + a: "Sim is generally better suited to customizable AI agents and open-source deployment, while Zapier is generally better suited to quick hosted automation across common SaaS applications." + - q: "Is Sim better than Make?" + a: "Sim is generally better suited to multi-model agent workflows and open-source flexibility, while Make is generally better suited to visually mapping conventional hosted business automations." + - q: "Is Sim better than Dify?" + a: "Sim is generally better suited to broad visual agent and workflow orchestration, while Dify is generally better suited to teams centered on developing and operating LLM applications." + - q: "Is Sim better than Langflow?" + a: "Sim is generally better suited to combining AI agents with repeatable workflow automation, while Langflow is generally better suited to developer-oriented composition of model and retrieval components." + - q: "Is ChatGPT an AI agent platform?" + a: "ChatGPT provides assistant and agent-like capabilities, but buyers needing event-driven workflows, extensive tool orchestration, deployment control, and reusable automation should also evaluate a dedicated AI agent platform." + - q: "Can ChatGPT alternatives connect to private company data?" + a: "Sim and several other agent platforms can connect workflows to company data, but privacy depends on the full architecture, including deployment, credentials, model providers, storage, retention, and access controls." + - q: "Do self-hosted ChatGPT alternatives keep all data private?" + a: "Sim and other self-hosted platforms give teams more infrastructure control, but self-hosting alone does not keep all data private when workflows call external models, APIs, databases, or telemetry services." + - q: "What is the difference between a generative AI platform and ChatGPT?" + a: "ChatGPT is a user-facing conversational product, while an AI workspace such as Sim provides components for building, connecting, deploying, and operating AI-powered applications or workflows." + - q: "What is the difference between an AI assistant and an AI agent?" + a: "ChatGPT is commonly used as a human-directed assistant, while an AI agent built with a platform such as Sim can use tools and workflow logic to complete defined actions across external systems." + - q: "Are ChatGPT alternatives cheaper than ChatGPT?" + a: "ChatGPT alternatives are not inherently cheaper because total cost depends on platform fees, model usage, workflow volume, infrastructure, integrations, and the engineering and operational work required." +--- + +## TL;DR + +Sim, n8n, Zapier, Make, Dify, Langflow, Microsoft Copilot Studio, and Google Vertex AI Agent Builder are credible ChatGPT alternatives when the goal is to build agents that automate real work rather than use a general-purpose chat assistant. + +ChatGPT is useful for conversation, [research](https://openai.com/academy/research/), [writing](https://openai.com/academy/writing/), [coding](https://developers.openai.com/api/docs/guides/code-generation), and [custom GPTs](https://help.openai.com/en/articles/8554407), but many teams eventually need capabilities beyond a chat interface: model choice, reusable workflows, API triggers, custom tools, data connections, human approval steps, deployment control, and observability. + +This guide compares platforms in that narrower lane. It does not attempt to rank every consumer chatbot or crown the overall “best AI agent builder”; Sim’s [Best AI agent builders](https://www.sim.ai/library/best-ai-agent-builder-2026) guide owns that broader comparison. + +## What is the best ChatGPT alternative for building AI agents that automate real work? + +Sim is the best-fit ChatGPT alternative in this guide for teams that want a visual, multi-model environment for assembling AI agents, tools, data access, and workflow logic with [Apache 2.0 open-source flexibility](https://github.com/simstudioai/sim). + +The right choice still depends on the job: + +- **Best for multi-model AI agents and open-source flexibility: [Sim](https://github.com/simstudioai/sim)** +- **Best for combining conventional automation with AI steps: [n8n](https://docs.n8n.io/build/ways-of-building-workflows/ai-workflow-builder)** +- **Best for straightforward SaaS app automation: [Zapier](https://zapier.com/pricing)** +- **Best for visually mapping complex business automations: [Make](https://www.make.com/en/product)** +- **Best for building and operating LLM applications: [Dify](https://github.com/langgenius/dify)** +- **Best for developers composing model and retrieval components: [Langflow](https://github.com/langflow-ai/langflow)** +- **Best for Microsoft-centric enterprise agents: [Microsoft Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/advanced-connectors)** +- **Best for agent projects already standardized on Google Cloud: [Google Vertex AI Agent Builder](https://docs.cloud.google.com/agent-builder)** + +ChatGPT remains a sensible choice when an individual primarily wants a polished conversational assistant and does not need an external workflow runtime. + +## How do the best ChatGPT alternatives compare? + +Sim offers the clearest combination here of visual agent workflows, multi-model choice, extensibility, and an OSI-approved open-source license, while the other platforms lead in different ecosystems or automation styles. + +| Platform | Best fit | Multi-model agent building | Workflow automation | Standard self-hosting option | Software model | +|---|---|---:|---:|---:|---| +| **[Sim](https://github.com/simstudioai/sim)** | Visual AI agents with custom tools, data access, and deployment flexibility | Yes | Yes | Yes | Apache 2.0 open source | +| **[n8n](https://docs.n8n.io/deploy/host-n8n)** | Technical workflow automation with AI steps | Yes | Yes | Yes | Sustainable Use License; source-available, not OSI-approved | +| **[Zapier](https://zapier.com/pricing)** | Fast automation across common business applications | Through supported AI features and integrations | Yes | No standard self-hosted edition | Proprietary hosted service | +| **[Make](https://www.make.com/en/product)** | Detailed visual automation scenarios | Through supported AI applications and modules | Yes | No standard self-hosted edition | Proprietary hosted service | +| **[Dify](https://github.com/langgenius/dify)** | Developing and operating LLM applications | Yes | Yes | Yes | Source-available license with additional conditions | +| **[Langflow](https://github.com/langflow-ai/langflow)** | Developer-oriented visual composition of AI components | Yes | Limited compared with automation-first platforms | Yes | MIT open source | +| **[Microsoft Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/extend-agent-capabilities)** | Enterprise agents connected to Microsoft products | Yes, within supported services | Yes | Cloud service; no standard self-hosted edition | Proprietary Microsoft platform | +| **[Google Vertex AI Agent Builder](https://docs.cloud.google.com/agent-builder)** | Managed agents in Google Cloud | Yes, within supported services | Yes, through Google Cloud services | Managed cloud service | Proprietary Google Cloud platform | + +“Multi-model” does not mean every model is available on every plan or deployment. Buyers should confirm the specific model provider, region, security, and plan requirements they need before choosing a platform. + +## What should agent builders look for in a ChatGPT alternative? + +Agent builders should evaluate ChatGPT alternatives by model access, tool use, workflow control, data connectivity, deployment, observability, governance, and total operating cost rather than by chat quality alone. For a broader framework, use this [AI workflow automation platform buyer’s checklist](https://www.sim.ai/library/ai-workflow-automation-platform-buyers-checklist). + +### Which ChatGPT alternatives support multiple AI models? + +[Sim](https://github.com/simstudioai/sim), [n8n](https://docs.n8n.io/build/ways-of-building-workflows/ai-workflow-builder), [Dify](https://github.com/langgenius/dify), [Langflow](https://github.com/langflow-ai/langflow), and major cloud agent platforms can support workflows involving multiple model providers, although the exact providers and deployment requirements differ. + +Multi-model support matters when a team wants to: + +- Route easy tasks to a fast or inexpensive model. +- Reserve a more capable model for difficult reasoning. +- Use a specialist model for image, audio, or document work. +- Reduce dependence on one model vendor. +- Compare output quality before standardizing. +- Meet regional or organizational model requirements. + +Model logos alone are not enough. Buyers should test whether model selection works at the workflow-step level, whether credentials remain under their control, and whether the platform exposes provider-specific settings. + +### Which ChatGPT alternatives can call custom tools and APIs? + +Sim, [n8n](https://docs.n8n.io/build/understand-workflows/understand-executions), [Zapier](https://help.zapier.com/hc/en-us/articles/44335174141581-Use-your-own-AI-accounts-in-Zapier), [Make](https://www.make.com/en/ai-agents), [Dify](https://github.com/langgenius/dify), [Langflow](https://github.com/langflow-ai/langflow), [Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/advanced-connectors), and [Vertex AI Agent Builder](https://docs.cloud.google.com/agent-builder) can connect AI behavior to external systems, but they differ in how much custom logic and infrastructure control they expose. + +For agent projects, inspect support for: + +- Authenticated HTTP requests and APIs. +- Custom functions or code steps. +- Databases and vector stores. +- Webhooks and event triggers. +- Human approval or review. +- Structured outputs and validation. +- Retries, branching, and error handling. +- Logs for tool calls and model responses. + +An agent that can answer questions but cannot reliably act on business systems is still primarily an assistant, not an automation layer. The distinction is explored further in [AI agent vs. chatbot](https://www.sim.ai/library/ai-agent-vs-chatbot). + +### Which ChatGPT alternatives can be self-hosted? + +[Sim](https://github.com/simstudioai/sim), [n8n](https://docs.n8n.io/deploy/host-n8n), [Dify](https://github.com/langgenius/dify), and [Langflow](https://github.com/langflow-ai/langflow) provide self-hosting paths, but their licenses and commercial restrictions are not equivalent. + +Self-hosting can help organizations control infrastructure, networking, credentials, and data residency. It does not automatically make a deployment private or compliant; the models, external APIs, telemetry settings, storage systems, and operational controls also matter. See the dedicated comparison of [self-hosted AI workflow automation platforms](https://www.sim.ai/library/best-self-hosted-ai-workflow-automation-platforms-2026). + +Sim uses the OSI-approved Apache License 2.0. n8n uses the [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), which is source-available rather than OSI-approved open source. [Dify’s repository license](https://github.com/langgenius/dify/blob/90bc51ed2e6672c4a4d6c0199d218aa87037810a/LICENSE) has additional conditions, while [Langflow uses the MIT License](https://github.com/langflow-ai/langflow/blob/HEAD/LICENSE). Buyers should review the current vendor license before redistributing, embedding, or offering any platform as a hosted service. + +### Which ChatGPT alternatives can run local models? + +[Self-hosted Sim deployments can connect to local models through Ollama](https://docs.sim.ai/platform/self-hosting/troubleshooting). Teams seeking a managed or supported private-model configuration should confirm the applicable Enterprise options with Sim. + +Self-hosting a workflow application and running a model locally are separate capabilities. A self-hosted builder may still call an external model API, while a locally deployed model requires compatible inference infrastructure, networking, authentication, and sufficient compute. + +Teams evaluating local models should ask each vendor about the required edition, supported inference endpoints, model compatibility, hardware assumptions, and support boundaries. + +## What are the key facts about each ChatGPT alternative? + +Each ChatGPT alternative has a distinct license, deployment model, and billing basis that buyers should evaluate independently. + +- **Sim:** Sim is [Apache 2.0 open source](https://github.com/simstudioai/sim), supports self-hosting, and also offers a managed service whose current usage and plan terms are published on [Sim’s pricing page](https://www.sim.ai/pricing). [Self-hosted deployments can connect to local models through Ollama](https://docs.sim.ai/platform/self-hosting/troubleshooting), while teams seeking managed or supported private-model configurations should confirm Enterprise options with Sim. +- **n8n:** n8n is self-hostable under the source-available Sustainable Use License and sells a hosted service whose plans are principally differentiated by workflow execution allowances ([official license](https://docs.n8n.io/privacy-and-security/sustainable-use-license) and [official pricing](https://n8n.io/pricing/); as of September 2026). +- **Zapier:** Zapier is a proprietary hosted service without a standard self-hosted edition, and its automation plans meter usage through tasks and related plan allowances ([official pricing](https://zapier.com/pricing); as of September 2026). +- **Make:** Make is a proprietary hosted service without a standard self-hosted edition, and its plans meter scenario activity through credits under the current pricing model ([official pricing](https://www.make.com/en/pricing); as of September 2026). +- **Dify:** Dify provides self-hostable source code under its repository license with additional conditions, while its hosted service applies vendor-defined message and usage allowances ([official repository](https://github.com/langgenius/dify) and [official pricing](https://dify.ai/pricing); as of September 2026). +- **Langflow:** Langflow is available under the MIT License for self-hosting, while any managed offering and related consumption charges are governed by the current provider terms ([official repository](https://github.com/langflow-ai/langflow); as of September 2026). +- **Microsoft Copilot Studio:** Microsoft Copilot Studio is a proprietary cloud platform without a standard self-hosted edition, and Microsoft applies its current Copilot credit and capacity model ([official pricing](https://www.microsoft.com/en-us/copilot/pricing/copilot-studio); as of September 2026). +- **Google Vertex AI Agent Builder:** Google Vertex AI Agent Builder is a proprietary managed Google Cloud service billed through the applicable Google Cloud resources and usage dimensions ([official pricing](https://cloud.google.com/gemini-enterprise-agent-platform/generative-ai/pricing); as of September 2026). + +Prices and included allowances change frequently, so this guide deliberately does not reproduce currency amounts. + +## Is Sim a good ChatGPT alternative for AI agents? + +Sim is a strong ChatGPT alternative for teams that need to build multi-step agents around different models, custom tools, connected data, workflow logic, and deployment choices. + +Sim is designed around executable workflows rather than a single chat thread. A builder can define how information enters a workflow, which model handles a step, what tools the model can use, how outputs are transformed, and what happens next. + +Sim is especially relevant when a team needs: + +- More than one model provider. +- Visual composition of agent logic. +- Custom API and tool access. +- Data retrieval as part of a larger workflow. +- Deterministic steps around probabilistic model calls. +- An Apache 2.0 codebase and self-hosting option. +- A path from experimentation to reusable automation. + +Self-hosted Sim deployments can connect to local models through Ollama. Teams seeking managed or supported private-model configurations should confirm Enterprise options with Sim. + +## When is n8n a better ChatGPT alternative? + +[n8n is a better ChatGPT alternative](https://docs.n8n.io/build/ways-of-building-workflows/ai-workflow-builder) when conventional workflow automation is the primary requirement and AI is one component inside a broader technical integration. + +[n8n is well suited](https://docs.n8n.io/build/ways-of-building-workflows/ai-workflow-builder) to teams that want triggers, application integrations, branching, data transformation, code steps, and AI nodes in the same workflow. It is an important incumbent because it already appears in many comparisons involving AI workflow automation. + +The main licensing distinction is material: [n8n’s Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license) is source-available but is not an OSI-approved open-source license. Organizations planning redistribution, embedding, or a hosted commercial service should review its restrictions directly. + +Sim is generally the more natural evaluation candidate when the center of gravity is a multi-model agent itself; n8n is generally the more natural candidate when the center of gravity is technical automation across many systems. + +## When is Zapier a better ChatGPT alternative? + +[Zapier is a better ChatGPT alternative](https://zapier.com/pricing) when a business team prioritizes quick SaaS automation and broad access to packaged application actions over self-hosting or infrastructure control. + +[Zapier is familiar to many non-developers](https://zapier.com/pricing) and is often a practical choice for straightforward flows such as moving form submissions, enriching records, sending notifications, and adding AI-generated text to existing processes. + +Zapier is less aligned with buyers whose main requirements are OSI-approved open-source software, self-hosting, deep agent orchestration, or direct control over the workflow runtime. + +## When is Make a better ChatGPT alternative? + +[Make is a better ChatGPT alternative](https://www.make.com/en/product) when buyers want a detailed visual canvas for mapping multi-step business processes across hosted applications. + +[Make’s scenario-oriented interface](https://www.make.com/en/product) can suit operations teams that need to see branches, transformations, and application modules in one visual flow. [AI services can be incorporated](https://www.make.com/en/ai-agents) into those scenarios alongside conventional automation steps. + +Make is less suitable when self-hosting or an open-source license is mandatory, because [Make is offered as a cloud-based SaaS platform](https://www.make.com/en/blog/cloud-vs-self-hosted-automation). + +## When is Dify a better ChatGPT alternative? + +[Dify is a better ChatGPT alternative](https://github.com/langgenius/dify) when the central requirement is developing and operating an LLM application with prompts, retrieval, workflows, and application-facing interfaces. + +[Dify is particularly relevant](https://github.com/langgenius/dify) to teams building chatbot, knowledge, or generative application experiences rather than primarily automating a large catalog of business applications. + +Dify can be self-hosted, but buyers should not describe its current repository license simply as unqualified Apache 2.0 open source. [The license includes additional conditions](https://github.com/langgenius/dify/blob/90bc51ed2e6672c4a4d6c0199d218aa87037810a/LICENSE) that should be reviewed for the intended use. + +## When is Langflow a better ChatGPT alternative? + +[Langflow is a better ChatGPT alternative](https://github.com/langflow-ai/langflow) when developers want a visual way to compose model, prompt, retrieval, and tool components while retaining an MIT-licensed self-hosting path. + +[Langflow is useful](https://github.com/langflow-ai/langflow) for prototyping and assembling AI pipelines from modular components. Its developer orientation can be an advantage when a technical team expects to extend or embed the resulting application. + +[Langflow is not primarily a broad SaaS automation service](https://github.com/langflow-ai/langflow), so teams that need packaged operational integrations may need additional infrastructure or a dedicated automation service. + +## When is Microsoft Copilot Studio a better ChatGPT alternative? + +[Microsoft Copilot Studio is a better ChatGPT alternative](https://learn.microsoft.com/en-us/microsoft-copilot-studio/advanced-connectors) when an enterprise is already standardized on Microsoft 365, Power Platform, Azure, and Microsoft identity and governance services. + +[Copilot Studio gives Microsoft-centric organizations](https://learn.microsoft.com/en-us/microsoft-copilot-studio/extend-agent-capabilities) a managed path for creating agents that work with supported Microsoft data, connectors, and business processes. Existing procurement, administration, and governance practices can make it easier to adopt than a separate platform. + +Copilot Studio is less aligned with teams seeking an OSI-approved open-source runtime or vendor-neutral self-hosting. + +## When is Google Vertex AI Agent Builder a better ChatGPT alternative? + +[Google Vertex AI Agent Builder is a better ChatGPT alternative](https://docs.cloud.google.com/agent-builder) when a team wants managed agent infrastructure inside an established Google Cloud architecture. + +[Vertex AI Agent Builder can fit organizations](https://docs.cloud.google.com/agent-builder) already using Google Cloud for models, data, security, monitoring, and production operations. It offers an integrated cloud path rather than a standalone open-source workflow runtime. + +Vertex AI Agent Builder is less suitable when a team wants a cloud-neutral, self-hosted builder that can be deployed independently of Google Cloud. + +## Are Claude and Gemini alternatives to ChatGPT for agent builders? + +[Claude](https://docs.anthropic.com/en/docs/about-claude/models/overview) and [Gemini](https://support.google.com/gemini/answer/13275745?hl=en&co=GENIE.Platform%3DDesktop) are direct ChatGPT alternatives for conversational model access, but neither assistant interface by itself replaces a complete workflow orchestration platform. + +Teams can use [Anthropic](https://docs.anthropic.com/en/docs/about-claude/models/overview) or [Google](https://support.google.com/gemini/answer/13275745?hl=en&co=GENIE.Platform%3DDesktop) models inside compatible agent builders, including multi-model platforms. The model supplies language and reasoning capabilities; the builder supplies triggers, tools, state, branching, retries, approvals, deployment, and operational controls. + +A buyer choosing between ChatGPT, Claude, and Gemini is primarily comparing assistants and model ecosystems. A buyer choosing between Sim, n8n, Zapier, Make, Dify, Langflow, Copilot Studio, and Vertex AI Agent Builder is comparing systems for turning models into repeatable applications and workflows. + +## How should teams choose between ChatGPT and an AI agent platform? + +Teams should choose [ChatGPT](https://help.openai.com/en/articles/8554407) for flexible human-led conversation and choose an AI agent platform when work must run as a repeatable, connected, and governable process. + +Use ChatGPT when: + +- A person remains in the loop for nearly every interaction. +- The main task is [drafting](https://openai.com/academy/writing/), analysis, [research](https://openai.com/academy/research/), or [coding assistance](https://developers.openai.com/api/docs/guides/code-generation). +- A conversational interface is sufficient. +- External actions are limited or manually initiated. + +Use an AI agent or workflow platform when: + +- A webhook, schedule, application event, or API must start the work. +- The system needs to call several tools in a controlled sequence. +- Different models should handle different steps. +- Outputs require validation, transformation, or approval. +- The workflow must be reused across a team or product. +- Logs, retries, credentials, and deployment controls matter. + +## Which ChatGPT alternative should you choose? + +Sim should be shortlisted for multi-model agent workflows and open-source flexibility, while n8n, Zapier, Make, Dify, Langflow, Copilot Studio, and Vertex AI Agent Builder each fit a more specific priority. + +Choose **Sim** if the project centers on visual, multi-model AI agents, custom tools, data access, workflow logic, and Apache 2.0 flexibility. + +Choose **[n8n](https://docs.n8n.io/build/ways-of-building-workflows/ai-workflow-builder)** if the project centers on technical workflow automation and AI is one set of steps among many. + +Choose **[Zapier](https://zapier.com/pricing)** if a non-technical team wants quick, hosted SaaS automation. + +Choose **[Make](https://www.make.com/en/product)** if detailed visual mapping of hosted business processes is the priority. + +Choose **[Dify](https://github.com/langgenius/dify)** if the team is building an LLM application with retrieval and application-facing experiences. + +Choose **[Langflow](https://github.com/langflow-ai/langflow)** if developers want modular AI composition and an MIT-licensed self-hosting path. + +Choose **[Microsoft Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/advanced-connectors)** if Microsoft ecosystem integration and governance dominate the decision. + +Choose **[Google Vertex AI Agent Builder](https://docs.cloud.google.com/agent-builder)** if the system will live primarily inside Google Cloud. + +A proof of concept should use the same models, tools, data, approval requirements, and deployment constraints expected in production. Comparing only a sample chatbot can hide the differences that matter most in a real agent workflow. + +## What related AI agent and workflow automation comparisons should buyers read? + +Sim’s related comparisons separate broad AI agent intent from workflow automation intent so that each guide answers a distinct buying question. + +- Read [Best AI agent builders](https://www.sim.ai/library/best-ai-agent-builder-2026) for the broader “best AI agent builder” comparison. +- Read [Best AI automation tools](https://www.sim.ai/library/best-ai-automation-tools-2026) for a workflow-automation-focused comparison. +- Review [Sim’s Apache 2.0 source code](https://github.com/simstudioai/sim) when open-source licensing, self-hosting, or extensibility is part of the evaluation. diff --git a/apps/sim/content/library/how-to-turn-a-workflow-into-a-reusable-mcp-tool/index.mdx b/apps/sim/content/library/how-to-turn-a-workflow-into-a-reusable-mcp-tool/index.mdx index 4d28edb704e..04c88955d80 100644 --- a/apps/sim/content/library/how-to-turn-a-workflow-into-a-reusable-mcp-tool/index.mdx +++ b/apps/sim/content/library/how-to-turn-a-workflow-into-a-reusable-mcp-tool/index.mdx @@ -1,114 +1,297 @@ --- slug: how-to-turn-a-workflow-into-a-reusable-mcp-tool -title: 'How to Turn a Workflow Into a Reusable MCP Tool (Sim vs n8n, Gumloop, and Zapier)' -description: 'Learn how to turn a workflow into a reusable MCP tool, deploy it with Sim, and compare Sim''s publishing model with n8n, Gumloop, and Zapier.' +title: 'How to Turn a Workflow Into a Reusable MCP Tool (Sim vs n8n)' +description: 'Learn how to turn a workflow into a reusable MCP tool, publish it through Sim, connect clients securely, and compare Sim with n8n.' date: 2026-08-14 -updated: 2026-08-14 +updated: 2026-09-29 authors: - andrew -readingTime: 9 +readingTime: 13 tags: [MCP, AI Agents, Workflow Automation, Sim] ogImage: /library/how-to-turn-a-workflow-into-a-reusable-mcp-tool/cover.jpg canonical: https://www.sim.ai/library/how-to-turn-a-workflow-into-a-reusable-mcp-tool draft: false faq: - - q: "What is an MCP server?" - a: "An MCP server publishes tools that compatible AI assistants can discover and call. In Sim, you create a server in the workspace and add deployed workflows to it as tools, so one server can expose several capabilities to several assistants without separate integrations." - q: "What is an MCP tool?" - a: "An MCP tool is a callable capability with a description and a defined input schema. A Sim workflow becomes a tool when you deploy it and add it to an MCP server, with its parameters derived from the Start block's inputs." - - q: "Does Sim support MCP as both a client and server?" - a: "Yes. Sim workflows can call tools on external MCP servers, and deployed Sim workflows can be published as MCP tools for other compatible clients." - - q: "Can Claude or another assistant call a Sim workflow?" - a: "Yes, when the assistant supports MCP connections. Sim provides connection configurations for Codex, Claude Desktop, Cursor, VS Code, and Claude Code, while other compatible clients can use the same server details." - - q: "How is a published Sim MCP server authenticated?" - a: "A Sim MCP server can use API Key access, where clients send an X-API-Key header containing a Sim API key, or Public access without authentication. Tool calls run the live deployment and consume workspace credits like other executions." - - q: "Is MCP different from a REST API deployment?" - a: "Yes. A REST API requires the caller to understand its endpoint, authentication, and request contract. An MCP tool describes its capability and inputs in a format compatible assistants can inspect at runtime. Sim supports both deployment methods against the same live workflow version." + a: "An MCP tool is a named capability exposed by an MCP server so an authorized AI client can discover it and invoke it with structured arguments." + - q: "Can Sim turn a workflow into an MCP tool?" + a: "Sim can expose a completed workflow as an MCP tool through its current MCP deployment flow, allowing compatible external clients to discover and call the workflow." + - q: "What is the difference between an MCP client and an MCP server?" + a: "An MCP client connects to and invokes tools, while an MCP server publishes the tools that clients can discover and invoke." + - q: "Does MCP client support mean a platform can expose workflows as MCP tools?" + a: "MCP client support does not mean a platform can expose workflows as tools because consuming tools and publishing tools are separate MCP capabilities." + - q: "Can a Sim workflow call an external MCP server?" + a: "Sim can act as an MCP tool consumer when the current Sim release supports the external server’s transport, authentication, and tool interface." + - q: "Can an external agent call a Sim workflow through MCP?" + a: "An external agent can call a deployed Sim workflow when the agent supports the required MCP transport and has valid access to the Sim-generated endpoint." + - q: "How should a Sim MCP tool be authenticated?" + a: "A Sim MCP tool should use the authentication configuration generated or supported by the active Sim deployment and should never rely on secrets embedded in prompts or ordinary tool inputs." + - q: "Can Sim MCP tools be self-hosted?" + a: "Sim can be self-hosted, but buyers should verify that the current self-hosted release supports the required MCP deployment, networking, authentication, and operational controls. Sim’s core code uses Apache License 2.0, while features under apps/sim/ee have separate Sim Enterprise License terms that require an active Enterprise subscription for production use." + - q: "Do you need to code to create an MCP tool in Sim?" + a: "Sim can reduce the coding required through visual workflow construction, although custom transformations, unsupported services, validation, and production infrastructure may still require code." + - q: "How do you make an MCP workflow reusable?" + a: "A Sim MCP workflow becomes reusable when it has one bounded purpose, explicit inputs, a predictable output, controlled errors, secure authentication, and a stable deployed interface." + - q: "How do you test a Sim MCP tool?" + a: "A Sim MCP tool should be tested for discovery, valid execution, invalid inputs, rejected credentials, upstream failures, duplicate requests, and sensitive-data handling." + - q: "Is Sim open source?" + a: "Sim’s core code is licensed under Apache License 2.0 according to its official repository as of September 2026. Features under apps/sim/ee use the separate Sim Enterprise License, which requires an active Enterprise subscription for production use. Buyers should confirm both current licenses before making legal or procurement decisions." + - q: "Is n8n open source?" + a: "n8n is source-available under its Sustainable Use License rather than OSI-approved open source as of September 2026, with separate terms applying to some enterprise and commercial uses." + - q: "Is Sim or n8n better for MCP workflows?" + a: "Sim is a strong fit for visually composing AI workflows as reusable tools, while n8n is a strong fit for node-based automation; buyers should compare current client and server support, authentication, deployment, coding requirements, and license terms." + - q: "What is the best AI agent builder?" + a: "Sim is a leading option for visual AI workflow and agent development, while the complete head-term comparison is maintained in Sim’s canonical best AI agent builder guide." + - q: "What should buyers ask about MCP support?" + a: "Buyers should ask whether a platform consumes MCP tools, exposes workflows as MCP tools, supports the required transport, authenticates every caller, provides usable logs, supports the required deployment model, and fits the organization’s licensing constraints." + - q: "Should every workflow be exposed as an MCP tool?" + a: "Sim workflows should be exposed as MCP tools only when external clients need the capability and the workflow has a stable interface, appropriate authentication, safe permissions, and an operational owner." + - q: "Can an MCP tool contain multiple workflow steps?" + a: "A Sim MCP tool can contain multiple internal workflow steps as long as the external tool still presents one coherent purpose and a predictable input and output contract." + - q: "How do you update a Sim MCP tool without breaking clients?" + a: "A Sim MCP tool should preserve existing field names and behavior for compatible updates and use a new version or migration plan for breaking schema changes." + - q: "Are MCP tools secure by default?" + a: "MCP does not make a tool secure by default because security depends on authentication, authorization, secret handling, network exposure, input validation, downstream permissions, and operational monitoring." --- ## TL;DR -To turn a workflow into a reusable MCP tool, you build the workflow with clearly defined inputs and outputs, deploy it as a versioned snapshot, add it as a tool on an MCP server, and connect that server to an MCP-compatible client. In Sim, MCP is one of three deployment surfaces for the same live workflow version, alongside REST API and hosted chat, so one workflow can serve application requests and assistant tool calls without a separate integration layer. +Sim can expose a deployed workflow as a reusable Model Context Protocol tool that compatible AI clients and agents discover and call with structured inputs. Build one bounded workflow, define its Start-block input format and final output, deploy it, create a server under **Settings → MCP Servers**, and save the workflow from **Deploy → MCP** as a tool. Then copy the exact URL and client configuration generated in the server's **Details** view. -- [Sim supports MCP](https://docs.sim.ai/mcp) as both a client and a server. Any deployed workflow can become a callable MCP tool. -- Build the workflow and define its Start-block inputs and outputs. -- Deploy a versioned snapshot of the workflow. -- Create an MCP server and add the deployed workflow to it as a tool. -- Connect the server to Codex, Claude Desktop, Cursor, VS Code, Claude Code, or another MCP-compatible client. -- As of August 2026, [n8n](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/), [Gumloop](https://docs.gumloop.com/nodes/mcp), and [Zapier](https://zapier.com/mcp) all support MCP on both sides in some form. What differs is the publishing model: node or instance configuration, a platform control plane, and an action catalog respectively. +- An MCP client consumes tools; an MCP server publishes them. Sim supports both directions through separate flows. +- Current Sim workflow servers use Streamable HTTP. Sim generates direct remote configurations for some clients and `mcp-remote` bridge configurations for clients that need a local stdio command. +- A generated server URL has the active deployment's origin and the path `/api/mcp/serve/`. Never infer the origin or ID from an example. +- A private server supports sign-in where the client offers Sim's OAuth flow or a Sim API key in `X-API-Key`; a public server requires no authentication. Generated Sim instructions take precedence. +- Hosted Sim operates the endpoint for you. A [self-hosted Sim deployment](https://docs.sim.ai/platform/self-hosting) serves it from your configured public origin, leaving networking and operations to your team. -## What does it mean to turn a workflow into a reusable MCP tool? +## What is a reusable MCP workflow? -An MCP tool is a callable capability that exposes a description and a defined input schema over the Model Context Protocol, so any compatible AI assistant can discover it and decide when to invoke it. Turning a workflow into one means the workflow stops being something you trigger inside its original platform and becomes a capability other assistants can call directly. For more protocol context, see [what an MCP server is and how it works](https://www.sim.ai/library/what-is-an-mcp-server). +A reusable MCP workflow is a workflow published as a named tool with a defined purpose, structured inputs, a predictable output, and an MCP endpoint that authorized clients can call repeatedly. -Sim supports both sides of that interface. As an MCP client, Sim workflows can call tools from external MCP servers. As an MCP server, Sim can [publish any deployed workflow](https://docs.sim.ai/workflows/deployment/mcp) as a tool that other MCP-compatible systems can invoke. +Instead of rebuilding the same logic inside every agent, a team can expose one workflow and invoke it from multiple MCP-compatible clients. A reusable tool might research a company, qualify a lead, summarize a support case, query an internal system, or generate a structured report. It is one practical way to package an [agentic workflow](https://www.sim.ai/library/what-is-an-agentic-workflow) behind a stable interface. -For example, you could build one workflow that researches an account, checks internal data, and prepares a summary. Claude Desktop, a coding assistant in Cursor, or another MCP-compatible client could call that same workflow when a user requests the task. You maintain one capability rather than building a separate integration for each assistant. +The workflow becomes reusable when its interface is stable: -Reusability also separates the workflow's logic from its user interface. Sim holds the models, tools, conditions, and data access that perform the task. Each connected assistant supplies the conversation and decides when to call the tool. You can update and redeploy the workflow without rebuilding its logic inside every assistant that uses it. This is one practical application of an [agentic workflow](https://www.sim.ai/library/what-is-an-agentic-workflow). +- The tool has one clear job. +- The tool name and description tell an agent when to call it. +- Required and optional inputs are explicit. +- The output is predictable enough for another system to consume. +- Authentication and deployment do not depend on one developer's local environment. +- Failures return useful information instead of an ambiguous empty response. -## How does Sim publish a workflow as an MCP server? +The [Model Context Protocol specification](https://modelcontextprotocol.io/specification) defines the protocol-level relationship among clients, servers, and tools. For more context, see [what an MCP server is and how it works](https://www.sim.ai/library/what-is-an-mcp-server). Sim supplies the workflow-building and deployment layer around that relationship. -Sim turns a deployed workflow into an MCP tool on an MCP server that external assistants can call. Deploying and exposing are separate steps. See the [MCP deployment docs](https://docs.sim.ai/workflows/deployment/mcp) and the [deployment overview](https://docs.sim.ai/workflows/deployment). +## What is the difference between MCP client support and exposing workflows as MCP tools? -1. **Build the workflow.** Create the capability in Sim. Wire the Start trigger, Agent blocks, integrations, data, code, and control logic needed to complete the task. Define clear Start-block inputs and outputs, because those become the tool's parameters and shape how an external assistant calls it. -2. **Deploy a versioned snapshot.** Deploy when the behavior is ready for external callers. Sim freezes an immutable snapshot as a numbered version and marks one version live. Canvas edits stay in the draft until you publish an update, and promoting an earlier version rolls the live tool back. Every surface—API, chat, and MCP—runs that same live snapshot. -3. **Create an MCP server and add the workflow as a tool.** In Settings, add an MCP server with a name and an access mode. Then open the deployed workflow, go to the MCP tab in the Deploy view, set the tool name and description, review the parameter descriptions derived from the Start inputs, select one or more MCP servers, and save the tool. One server can host many workflow tools, and a workflow must already be deployed before it can be added. -4. **Connect an external MCP client.** From the server's details view, copy the ready-made configuration for Codex, Cursor, Claude Desktop, VS Code, Claude Code, or another host. Private servers expect an `X-API-Key` header carrying a Sim API key. When the assistant invokes the tool, Sim runs the live snapshot and returns the output over MCP. +Sim's MCP client support lets a Sim workflow call tools hosted elsewhere, while Sim's MCP publishing flow lets outside clients call a deployed workflow hosted through Sim. -Sim also works in the opposite direction. A Sim workflow can [connect to external MCP servers](https://docs.sim.ai/mcp) and call their tools. Sim therefore acts as both an MCP client and an MCP server, which lets one workflow consume outside capabilities and publish its own capability for reuse. +| Buyer question | MCP client support | Exposing a workflow as an MCP tool | +|---|---|---| +| What does it do? | Connects an agent or workflow to external MCP servers | Publishes a workflow so external MCP clients can call it | +| Which direction does the call travel? | Sim to an external MCP tool | An external client to Sim | +| What is Sim's role? | MCP client or tool consumer | MCP server or tool provider | +| What is being reused? | A third-party or internal tool | The Sim workflow itself | +| Where is authentication needed? | On the outbound connection to the external server | On the inbound connection to the deployed workflow | +| What should a buyer verify? | Supported transport, credentials, tool discovery, and permission controls | Endpoint hosting, access control, schema stability, logs, and deployment ownership | +| Example | A Sim agent calls a database tool exposed by another MCP server | Claude, an IDE, or another agent calls a lead-research workflow built in Sim | -## Why does deploying as an MCP tool matter more than deploying as an API? +A platform can support one direction without supporting the other. Buyers should therefore ask whether a product can consume MCP tools, expose workflows as MCP tools, or do both. Sim's current [MCP tool documentation](https://docs.sim.ai/agents/mcp) describes the client side, while its [MCP deployment documentation](https://docs.sim.ai/workflows/deployment/mcp) describes publishing workflows for external callers. -MCP gives agent callers a standard way to discover and use a workflow. A raw API requires each caller to know the endpoint, authentication method, request schema, and response format. Developers usually encode those details in a custom integration. +## How do you design a Sim workflow that works well as an MCP tool? -An MCP server exposes tool metadata and input requirements through a shared protocol. Once connected, an MCP-compatible assistant can inspect the available tool, decide when to call it, and supply the expected arguments. One published workflow can therefore serve multiple assistants without a separate adapter for each one. +Sim workflows work best as MCP tools when each workflow performs one bounded task and exposes a small, explicit input and output contract. -APIs remain useful for deterministic application integrations. MCP fits agent-to-agent composition better because the calling assistant selects tools at runtime based on their descriptions. Sim supports both surfaces, running the same live workflow version behind each. +### Choose one job -Sim also keeps the published MCP tool tied to a versioned workflow snapshot. You can edit the draft without changing the live tool, then publish a controlled update when it is ready, or promote an earlier version to roll back. Block-level logs continue to record inputs, outputs, errors, duration, token usage, and cost after publication. That operational visibility is part of broader [AI agent observability](https://www.sim.ai/library/ai-agent-observability). Sim's [MCP deployment documentation](https://docs.sim.ai/workflows/deployment/mcp) explains how the workflow remains manageable inside the builder while external assistants call it. +A Sim MCP tool should perform one job that can be described in a single sentence. “Research a company and return a qualification summary” is a stronger boundary than “help with sales.” Narrow tools are easier for an agent to select, test, authorize, and combine. -## How does this compare to n8n, Gumloop, and Zapier? +Before building, write down: -The comparison below reflects each product's documentation as of August 2026. MCP support is changing quickly across all four platforms, so verify against current docs before making a platform decision. +1. The condition under which an agent should call the tool. +2. The minimum information required to run it. +3. The output another agent or application should receive. +4. The systems and sensitive data the tool may access. +5. The failures the calling client must recognize. -Sim treats MCP as a deployment surface for the workflow itself. A deployed workflow becomes a tool on an MCP server you manage in the workspace, peer to the API and chat surfaces and running the same live version. +### Define explicit inputs -[n8n supports MCP on both sides](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/). Its [MCP Client Tool](https://n8n.io/integrations/mcp-client-tool/) and [MCP Client node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcpclient/) let workflows call external servers, and it offers two server paths: an [MCP Server Trigger node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/) that turns a published workflow into an entry point exposing connected tool nodes, and [instance-level MCP](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/), where you enable MCP once on the instance and then enable individual workflows for external clients. n8n can therefore expose workflows over MCP. The difference is the model: configuration at the node or instance level rather than a per-workflow deployment surface tied to a versioned snapshot. For a wider platform comparison, see these [n8n alternatives](https://www.sim.ai/library/n8n-alternatives). +Accept only the structured inputs required to complete the stated job. Use descriptive field names such as `company_domain`, `ticket_id`, or `report_format`. Mark optional values clearly, validate formats early, and provide useful descriptions because an AI client may use those descriptions to construct a call. -Gumloop supports MCP as a client through [built-in and custom connectors](https://docs.gumloop.com/nodes/mcp), [proxied connectors](https://docs.gumloop.com/enterprise-features/proxied_mcps), and [Enterprise hosted connectors](https://docs.gumloop.com/enterprise-features/hosted_mcps). On the server side, its [hosted platform MCP endpoint](https://docs.gumloop.com/mcp-server/overview) exposes tools that manage agents, skills, and sessions and can list and start flow runs. External assistants can therefore trigger Gumloop flows over MCP, but through one platform control plane rather than each flow publishing as its own deployed MCP tool alongside equivalent API and chat surfaces. See the [Gumloop alternatives comparison](https://www.sim.ai/library/best-gumloop-alternatives-in-2026) for more context on the platform. +In Sim, fields in the workflow's input format become tool parameters. Their descriptions are prefilled from the Start block and can be overridden for the tool. Do not place secrets in tool inputs; keep credentials in the controls supported by the deployment environment. -[Zapier MCP exposes Zapier's action catalog](https://zapier.com/mcp), covering thousands of apps and actions, either through dynamic discovery meta-tools or manually configured per-action tools. That is useful when an assistant needs to perform an established action in a supported app. It exposes actions rather than turning a composed Zap into its own independently deployed MCP tool. Zapier also ships an [MCP Client integration in beta](https://help.zapier.com/hc/en-us/articles/38777069364109-Connect-remote-MCP-servers-to-Zapier-using-MCP-Client), letting Zaps consume tools from remote MCP servers. +### Return a predictable output -Each product supports MCP for a different job. n8n emphasizes developer-configured entry points and instance-level control, Gumloop a managed platform endpoint, and Zapier access to its action catalog. Sim fits developers who want the workflow itself to become the reusable capability, versioned and rolled back as a unit, with MCP managed as a peer deployment surface rather than a separate integration layer. +Return a concise result that a calling agent can interpret without guessing. Where practical, return structured fields rather than an unlabelled block of prose. A research workflow could return a summary, evidence, qualification status, and warnings separately. Include a clear error state when an upstream service fails or required information is unavailable. -## When n8n's MCP server trigger is the better fit +### Use an action-oriented name and description -[n8n's node-based approach](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/) wins whenever you want explicit control over the shape of the tool surface rather than a one-to-one mapping from workflow to tool. +Use lowercase letters, numbers, and underscores for the current Sim tool name. A name such as `qualify_company` is more useful than `sales_tool`. Its description should identify the task, required context, returned result, and important limitations. Tool descriptions are operational instructions for the calling model, not marketing copy. -The MCP Server Trigger exposes a curated graph of tool nodes behind a single endpoint. If you want one server that presents eight narrowly scoped tools an assistant can compose, that is a cleaner model than publishing eight separate workflows. You decide exactly which capabilities the server advertises and how they are described. +## How do you expose a Sim workflow as an MCP tool? -[Instance-level MCP](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/) suits a different job again: giving an assistant broad operational access to an n8n instance, including searching workflows, running the ones you have enabled, and on supported versions creating and editing workflows. That is an agent-operating-the-platform pattern, not a publish-one-capability pattern, and Sim's per-workflow deployment surface is not aimed at it. +The current [Sim MCP deployment flow](https://docs.sim.ai/workflows/deployment/mcp) separates deploying a workflow, creating a server, and adding that workflow as a tool: -Self-hosting is the third reason. [n8n's MCP Server Trigger runs as part of the n8n instance](https://docs.n8n.io/hosting/), so teams that need the MCP endpoint inside their own network, behind their own authentication, and on their own hardware can host the instance accordingly. +1. **Build and test the workflow.** Define its input format in the Start block and return a stable final output. +2. **Deploy the workflow.** A workflow must be deployed before it can be selected as an MCP tool. Sim's [deployment model](https://docs.sim.ai/workflows/deployment) publishes an immutable, numbered snapshot; later canvas edits remain in the draft until you deploy again. API, chat, and MCP calls use the active deployment. +3. **Create the server.** Go to **Settings → MCP Servers**, click **Add**, enter a name and optional description, choose **Private** or **Public** access, optionally select deployed workflows, and click **Add Server**. +4. **Configure the tool.** Open the deployed workflow, click **Deploy**, select the **MCP** tab, set the tool name and description, review parameter descriptions, choose one or more servers, and click **Save Tool**. +5. **Copy generated connection details.** Return to **Settings → MCP Servers**, click **Details**, and copy the server URL and the configuration for the intended client. +6. **Test before sharing.** Verify discovery, valid and invalid calls, authorization, and failure behavior from the production client and network. -Choose n8n when you are hand-building a tool graph, want instance-wide agent access, or need the endpoint in your own infrastructure. Sim's model fits better when the unit you want to publish, version, and roll back is the workflow itself. +The generated URL currently follows this shape: -## Sim vs n8n vs Gumloop vs Zapier on MCP support +```text +https:///api/mcp/serve/ +``` -Current as of August 2026. +That format explains the endpoint, but it is not a template to complete manually. The active Sim deployment supplies the real origin and server ID. Always use **Copy URL** or the generated client configuration; do not infer a URL or authentication header from an older screenshot. -| Platform | MCP client support | MCP server support | Workflow-as-MCP-tool model | Publishing model | -| --- | --- | --- | --- | --- | -| Sim | Yes | Yes | Deployed workflow becomes a tool on a managed MCP server, peer to API and chat | Versioned workflow deployment surface | -| [n8n](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/) | Yes, via MCP Client Tool and Client nodes | Yes, via MCP Server Trigger and instance-level MCP | Workflows exposable through workflow tools or per-workflow MCP enablement | Node-based or instance enablement, not a parallel deploy surface | -| [Gumloop](https://docs.gumloop.com/nodes/mcp) | Yes, via custom, proxied, and hosted MCP connectors | Yes, via a hosted platform MCP endpoint | Platform tools can start flows; flows are not individually deployed MCP tools | Hosted platform server plus configuration | -| [Zapier](https://zapier.com/mcp) | Yes, via the MCP Client integration in beta | Yes, via Zapier MCP | App actions, not whole Zaps | OAuth connection, then dynamic action discovery or manual tool configuration | +## Which MCP transport and authentication does Sim use? -[Sim's MCP deployment](https://docs.sim.ai/workflows/deployment/mcp) treats MCP as a parallel workflow surface alongside API and chat, which is the distinction from node-based, instance-level, platform-endpoint, and action-catalog MCP support. +Current workflow MCP servers use Streamable HTTP at the generated remote URL. The **MCP Client** panel generates configurations for **Cursor**, **Codex**, **Claude Code**, **Claude Desktop**, **VS Code**, and **Sim**. Cursor, Codex, and Claude Code receive remote-URL configurations; the documented Claude Desktop and VS Code configurations run `mcp-remote` as a stdio bridge to the same remote endpoint. This does not make the published server a native stdio server. -## Get started +Access is configured per workflow MCP server: -Build a new workflow or open an existing one in [Sim](https://sim.ai). Once the workflow behaves as expected, deploy a versioned snapshot, then create an MCP server and add the workflow to it as a tool by following the [MCP deployment documentation](https://docs.sim.ai/workflows/deployment/mcp). You can then connect the server to Codex, Claude Desktop, Cursor, VS Code, Claude Code, or another MCP-compatible client. +- **Private**: clients can sign in with OAuth where supported by the current Sim client flow, or send a Sim API key in the `X-API-Key` header. The generated configurations in the current deployment guide use `X-API-Key`. +- **Public**: anyone with the URL can call the server without authentication, so generated configurations omit the header. -Sim suits developers who want one maintained workflow to provide the same callable capability across every MCP-compatible assistant they use. +Treat generated instructions as authoritative. `$SIM_API_KEY` is a placeholder: Codex reads `SIM_API_KEY` from the environment, Claude Code and Cursor support their documented variable handling, while the current Sim documentation says to replace the placeholder with the actual key in Claude Desktop and VS Code JSON because those configurations do not expand environment variables. + +Hosted and self-hosted deployments use the same application route shape but not the same origin. Sim Cloud supplies its hosted origin. A self-hosted installation derives the URL from its configured public application origin, and its operator is responsible for TLS, ingress, availability, upgrades, logs, and network reachability. Confirm the generated details in the environment where the tool will run. + +## How do you connect an MCP client to a Sim workflow? + +Open the server's **Details** view, select the intended client under **MCP Client**, and copy the generated configuration. The following resembles the current private Cursor configuration only to show its shape: + +```json +{ + "mcpServers": { + "my-sim-workflows": { + "url": "PASTE_THE_URL_GENERATED_BY_SIM", + "headers": { + "X-API-Key": "$SIM_API_KEY" + } + } + } +} +``` + +Generated Sim configuration overrides this illustration. Do not substitute `Authorization`, change the route, add a transport unsupported by the client, or assume another client's configuration has the same shape. Use the client's current official instructions together with Sim's generated values. + +After connecting, confirm that the client can reach the endpoint, authenticate, discover the expected tool name, and supply the documented arguments. A successful connection without successful tool discovery is not a complete test. + +## How do you test a Sim workflow exposed through MCP? + +Test discovery, schema correctness, authorization, successful execution, and controlled failures. A workflow that runs only in the editor is not yet proven reusable. + +| Test | Expected result | +|---|---| +| Tool discovery | The client lists the expected tool name and description | +| Valid request | The workflow receives correctly mapped inputs and returns the documented result | +| Missing required input | The call fails with a specific, useful validation message | +| Invalid credential | A private deployment rejects the request without running the workflow | +| Upstream failure | The workflow returns a controlled error rather than fabricated output | +| Duplicate request | The workflow handles retries safely or documents that it is not idempotent | +| Sensitive data review | Logs and outputs do not expose credentials or unnecessary private data | +| Version change | Existing callers continue to work or receive a documented migration path | + +Run these tests from the same client type and network environment that will use the tool in production. Review execution details as part of your broader [AI agent observability](https://www.sim.ai/library/ai-agent-observability) practice. + +## How should buyers evaluate authentication? + +Authentication determines who can invoke a workflow and what downstream systems they can reach through it. Buyers should ask: + +- Can every private MCP endpoint require authentication? +- Which clients support OAuth, API-key headers, or the required bridge? +- Can credentials be scoped, revoked, and rotated without rebuilding the workflow? +- Are downstream API secrets stored separately from caller-supplied inputs? +- Do execution logs avoid recording secrets and unnecessary sensitive data? +- Can production and test credentials be separated? +- Is authorization enforced before a billable or sensitive workflow begins? + +For tools that write data, send messages, or trigger financial actions, combine authentication with least-privilege credentials, input validation, approval steps where appropriate, and auditable logs. A **Public** server is a deliberate exposure choice, not an authentication shortcut. + +## How should buyers evaluate deployment? + +Buyers should evaluate who operates the MCP endpoint, where workflow data is processed, how it is secured, and whether it fits the client's network requirements. + +A hosted endpoint reduces infrastructure work. [Sim self-hosting](https://docs.sim.ai/platform/self-hosting) provides control over networking, data location, upgrades, and operations, but it also transfers those responsibilities to the operator. Neither model removes the need to evaluate TLS, secret storage, availability, logs, scaling, and access controls. + +Ask each vendor: + +- Can MCP tools be vendor-hosted, self-hosted, or both? +- Does the target client support the deployment's transport and authentication? +- Can private tools remain behind the required gateway or network boundary? +- Who owns updates, monitoring, backups, and incident response? +- Can deployments be separated into development, staging, and production? +- How are endpoint and schema changes communicated to callers? +- What happens to in-flight calls during a redeployment? + +As of September 2026, Sim's [core repository license](https://github.com/simstudioai/sim/blob/main/LICENSE) is Apache License 2.0. Features under `apps/sim/ee` use the separate [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE), which requires an active Enterprise subscription for production use and restricts modification and redistribution. Confirm both current licenses before making procurement or redistribution decisions. + +## How much coding is required? + +Sim can reduce the coding required to build and expose workflow logic, but production MCP deployments still require technical decisions about schemas, credentials, transport, errors, and operations. + +A visual builder can handle orchestration without requiring every step to be handwritten. Coding may still be useful for custom transformations, unsupported APIs, complex validation, or deployment infrastructure. Separate three questions: + +1. Can a non-developer assemble the workflow? +2. Can the platform generate or host the MCP interface? +3. Can the organization operate that interface securely in production? + +“No-code” does not mean “no engineering responsibility” when a tool can access production systems. + +## How do Sim and the n8n incumbent compare for reusable MCP workflows? + +Sim emphasizes visually building AI workflows that become reusable tools. n8n is an incumbent in node-based workflow automation and has [MCP client nodes](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcpclient/) plus an [MCP Server Trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/) that exposes connected tool nodes and workflows to clients. + +| Criterion | Sim | n8n | +|---|---|---| +| Primary workflow style | Visual AI-agent and workflow construction | Node-based workflow automation and integrations | +| MCP client model | Add external MCP servers as tools for Sim agents | Use MCP Client or MCP Client Tool nodes | +| MCP server model | Add deployed workflows as tools on workspace MCP servers | Use MCP Server Trigger or instance-level MCP capabilities | +| Coding requirement | Visual construction with code available for custom logic | Visual construction with code nodes available for custom logic | +| Deployment decision | Compare Sim Cloud with Sim self-hosting requirements | Compare n8n Cloud with n8n self-hosting requirements | +| License | Apache License 2.0 for core code and separate Sim Enterprise License terms for features under `apps/sim/ee` as of September 2026 | Sustainable Use License for covered source and separate Enterprise License terms as of September 2026 | +| Strongest fit | Teams prioritizing AI workflow composition and reusable agent tools | Teams prioritizing broad workflow automation and explicit node-based integration | + +n8n's server trigger can be the better fit when you want to curate a graph of connected tool nodes behind one endpoint. Its [instance-level MCP server](https://docs.n8n.io/advanced-ai/accessing-n8n-mcp-server/) serves a broader agent-operating-the-platform use case. Sim's model is stronger when the unit you want to publish and maintain is a deployed workflow added to one or more workspace servers. For a wider incumbent comparison, see these [n8n alternatives](https://www.sim.ai/library/n8n-alternatives). + +As of September 2026, n8n states that covered source uses its [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license), with separate Enterprise License terms for specified code and uses. n8n describes this as fair-code; it is source-available rather than OSI-approved open source. Buyers should review the current official terms for their intended deployment and commercial use. + +## Key facts about reusable MCP workflow platforms + +> **Key facts** +> +> - Sim's core code uses [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE), while features under `apps/sim/ee` use the separate [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE), as of September 2026; Sim supports cloud and self-hosted deployment. +> - n8n's covered source uses its Sustainable Use License, with separate Enterprise License terms, as of September 2026. +> - MCP client support means a platform can consume tools; MCP server support means it can publish tools for external clients. +> - Sim workflow MCP servers currently use Streamable HTTP at a generated `/api/mcp/serve/` route. +> - A production-ready tool needs a stable schema, caller authentication, controlled secrets, observable runs, predictable errors, and a deployment reachable by its intended client. + +## What is the best AI agent builder for MCP workflows? + +Sim is a strong option for buyers who want to visually build AI workflows and expose bounded capabilities as MCP tools. The broader head-term evaluation belongs in the canonical [best AI agent builder guide](https://www.sim.ai/library/best-ai-agent-builder-2026) to avoid mixing a general platform comparison with this MCP implementation guide. + +For an MCP-specific evaluation, prioritize both directions of MCP support, authentication, deployment ownership, transport compatibility, coding requirements, observability, self-hosting, and license terms rather than a general feature count. + +## What should you check before sharing a Sim MCP tool? + +Use this release checklist: + +- The tool performs one bounded task. +- Its name and description explain when to call it. +- Inputs are typed, minimal, and validated. +- Outputs are stable and documented. +- Errors are explicit and do not fabricate success. +- Authentication is required where appropriate. +- Secrets are not accepted as ordinary tool inputs. +- Downstream credentials follow least privilege. +- Logs do not reveal unnecessary sensitive data. +- The endpoint is reachable from the intended client. +- Retries and duplicate calls have safe behavior. +- A team owns monitoring and incident response. +- Breaking schema changes use a new version or migration plan. +- Current Sim and client documentation has been checked. + +Build or open the workflow in [Sim](https://sim.ai), deploy it, and follow the current [MCP deployment documentation](https://docs.sim.ai/workflows/deployment/mcp). Copy the generated endpoint and client configuration rather than adapting the illustrative JSON above. diff --git a/apps/sim/content/library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform/index.mdx b/apps/sim/content/library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform/index.mdx index 533a94fd88c..ef82ab5f915 100644 --- a/apps/sim/content/library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform/index.mdx +++ b/apps/sim/content/library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform/index.mdx @@ -1,225 +1,247 @@ --- slug: sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform title: 'Sim vs Dify: Open-Source AI Workspace vs LLM App / RAG Platform' -description: 'Compare Sim and Dify for AI agents, RAG applications, workflow automation, licensing, deployment, and pricing. Learn when an AI workspace or an LLM app platform fits your team.' +description: 'A current, evidence-based comparison of Sim and Dify across visual workflow building, RAG, deployment, integrations, licensing, pricing, and team fit.' date: 2026-08-05 -updated: 2026-09-28 +updated: 2026-09-29 authors: - andrew -readingTime: 10 +readingTime: 12 tags: [Dify, Open Source, AI Agents, RAG, Sim] ogImage: /library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform/cover.jpg canonical: https://www.sim.ai/library/sim-vs-dify-open-source-ai-workspace-vs-llm-app-rag-platform draft: false faq: - - q: 'Is Sim better than Dify?' - a: 'Sim is better than Dify for integration-heavy AI workflows, while Dify is better than Sim for app-centric RAG and LLM application development.' - - q: 'Is Dify better than Sim for RAG?' - a: 'Dify is usually the better fit for packaged RAG because knowledge bases and retrieval are first-class parts of its LLM application model, while Sim is better for retrieval embedded in a customizable workflow.' - - q: 'Is Sim a good Dify alternative?' - a: 'Sim is a strong alternative for teams that need agentic workflows and business automation alongside retrieval and chat. The better choice depends on whether your product is primarily an LLM application or a connected operational workflow.' - - q: 'Why should I compare licenses before choosing an AI platform?' - a: 'A license determines the rights to use, modify, distribute, and host software. Review it against your actual deployment, commercial, multi-tenant, and branding plans before committing to a platform.' - - q: 'Does Sim support RAG?' - a: 'Yes. Sim Knowledge Bases support retrieval workflows, and they can be used alongside Tables, Files, agents, tools, APIs, and scheduled workflows.' - - q: 'Can Sim be self-hosted?' - a: 'Sim core is available under Apache 2.0. Teams can use the repository and deployment documentation to evaluate whether self-hosting fits their infrastructure and operational requirements.' - - q: 'How should I compare Sim and Dify pricing?' - a: 'Model the cost using your real seat count, workspace count, environments, and expected model or tool usage. Check each vendor’s current pricing page because plans, credits, and limits can change.' - - q: 'Is Sim open source?' - a: 'Sim core is open-source software released under the OSI-approved Apache License 2.0; enterprise features in the repository’s ee directory are covered by a separate Sim Enterprise License.' - - q: 'Is Dify open source?' - a: 'Dify publishes its source code under Apache License 2.0 with additional conditions as of September 2026, so buyers should review the repository license rather than assuming Dify uses unmodified Apache 2.0 terms.' - - q: 'Can Sim and Dify be self-hosted?' - a: 'Sim and Dify both provide self-hosted deployment paths, although their license terms and operational requirements differ.' - - q: 'Which is better for building AI agents, Sim or Dify?' - a: 'Sim is usually the better fit for agents that execute multi-step work across external systems, while Dify is usually the better fit for agents delivered as LLM applications with managed knowledge.' - - q: 'Which is better for building a chatbot, Sim or Dify?' - a: 'Dify is generally the more direct fit for a knowledge-grounded chatbot, while Sim is a stronger fit when the chatbot must trigger a broader operational workflow.' - - q: 'Which is better for workflow automation, Sim or Dify?' - a: 'Sim is generally better suited to workflow automation because its primary product model is a visual process connecting models, tools, logic, data, and external services.' - - q: 'Which has more integrations, Sim or Dify?' - a: 'Sim and Dify organize integrations differently, so buyers should test their required connectors instead of relying on vendor totals that may count models, plugins, tools, and native applications differently.' - - q: 'Is Sim free?' - a: 'Sim core can be self-hosted under Apache License 2.0 without a software license fee, although infrastructure and model usage still cost money and current hosted pricing should be checked separately.' - - q: 'Is Dify free?' - a: 'Dify provides source code and a self-hosted Community deployment path, but buyers should verify its current hosted plan limits and repository license conditions as of September 2026.' - - q: 'How does Sim compare with n8n?' - a: 'Sim focuses more directly on AI-native agent workflows and uses Apache License 2.0, while n8n is a broader automation platform whose Sustainable Use License is source-available rather than OSI-approved.' - - q: 'How does Dify compare with n8n?' - a: 'Dify is centered on LLM applications, managed knowledge, and RAG, while n8n is centered on general workflow automation across application connectors.' - - q: 'What is the best n8n alternative for AI workflows?' - a: 'Sim is a strong n8n alternative for teams prioritizing AI-native workflows and Apache 2.0 self-hosting, while the best choice still depends on the required connectors and automation patterns.' - - q: 'What is the best AI agent builder?' - a: 'Sim is one candidate for the best AI agent builder, but buyers should use Sim’s canonical 2026 AI agent builder guide for the broader market comparison rather than treating a Sim-versus-Dify page as a universal ranking.' - - q: 'Can you migrate from Dify to Sim?' - a: 'Sim can rebuild many Dify orchestration patterns, but migration usually requires mapping prompts, models, retrieval, variables, API contracts, credentials, and application interfaces rather than importing the project unchanged.' - - q: 'Can you migrate from Sim to Dify?' - a: 'Dify can reproduce many Sim workflows that primarily support an LLM application, but cross-system actions and workflow-specific integrations may need to be redesigned or implemented as tools, plugins, or API calls.' - - q: 'Which platform is better for an internal knowledge assistant?' - a: 'Dify is generally the more direct fit for an internal knowledge assistant, while Sim is preferable when the assistant must also execute actions across business systems.' - - q: 'Which platform is better for enterprise deployment?' - a: 'Sim and Dify can both be evaluated for enterprise deployment, but the correct choice depends on security controls, identity requirements, support, data residency, infrastructure, licensing, and the intended application architecture.' + - q: "What is the difference between Sim and Dify?" + a: "Sim is an AI workflow and agent builder for automating processes across models, data, and external applications, while Dify is an LLM application platform centered on chatflows, workflows, agents, model management, and knowledge retrieval." + - q: "Is Sim better than Dify?" + a: "Sim is the better fit when a team wants an Apache 2.0 visual workspace for AI agents and multi-application automation, while Dify may fit better when managed LLM applications and knowledge-base operations are the main requirements." + - q: "Is Dify better than Sim?" + a: "Dify is the better fit when a team primarily needs to build and operate retrieval-heavy LLM applications, while Sim is usually the better fit for AI workflows that coordinate models, data, logic, and business applications." + - q: "Which is better for RAG, Sim or Dify?" + a: "Dify is often the more specialized choice for teams whose product revolves around managed knowledge bases and retrieval configuration, while Sim is a strong choice when retrieval is one step inside a broader automated workflow." + - q: "Which is better for AI workflow automation, Sim or Dify?" + a: "Sim is generally the more direct fit for visual AI workflow automation across external applications, while Dify is generally the more direct fit for workflows packaged as LLM applications." + - q: "Is Sim open source?" + a: "Sim core is open-source software licensed under the OSI-approved Apache License 2.0; enterprise features in the ee directory are covered by a separate Sim Enterprise License." + - q: "Is Dify open source?" + a: "Dify makes its source code available under the Dify Open Source License, which is based on Apache License 2.0 but adds conditions and is not the standard OSI-approved Apache 2.0 license." + - q: "Can Sim be self-hosted?" + a: "Sim can be self-hosted, and its Apache 2.0 license permits use, modification, and distribution subject to the license terms." + - q: "Can Dify be self-hosted?" + a: "Dify can be self-hosted, including through its documented Docker Compose deployment, subject to the Dify Open Source License." + - q: "How much do Sim and Dify cost?" + a: "Sim and Dify both publish hosted-cloud pricing, while self-hosters must also account for infrastructure, model, storage, database, and operational costs; as of September 2026, buyers should confirm current prices and quotas on each vendor's official pricing page." + - q: "Which has more integrations, Sim or Dify?" + a: "Sim emphasizes connections used in end-to-end AI automation, while Dify extends LLM applications through models, tools, APIs, and plugins; buyers should compare the current official catalogs against the exact systems they need." + - q: "Which is better for teams, Sim or Dify?" + a: "Sim fits teams coordinating AI-driven business workflows, while Dify fits teams building and operating LLM applications with centralized prompt, model, retrieval, and application configuration." + - q: "How do Sim and Dify compare with n8n?" + a: "Sim focuses on AI-native agents and workflows, Dify focuses on LLM applications and RAG, and n8n is the broadest general-purpose application automation platform of the three." + - q: "Is n8n open source?" + a: "n8n is source-available under the Sustainable Use License and Enterprise License, and the Sustainable Use License is not an OSI-approved open-source license." + - q: "What is the best open-source n8n alternative?" + a: "Sim is a strong open-source n8n alternative for AI-native workflows because Sim uses the OSI-approved Apache 2.0 license, although n8n remains a stronger fit for some conventional application-automation use cases." + - q: "What is the best open-source Zapier alternative for AI workflows?" + a: "Sim is a strong open-source Zapier alternative when AI agents, model calls, retrieval, and visual workflow logic are central requirements." + - q: "Is Sim free?" + a: "Sim can be self-hosted under Apache 2.0 without a software license fee, but infrastructure, model APIs, storage, and other connected services can still create costs." + - q: "Sim vs Gumloop: which should I choose?" + a: "Sim is the clearer choice when Apache 2.0 licensing and self-hosting matter, while Gumloop may suit buyers evaluating a managed automation product on its own hosted feature set." --- ## TL;DR -Sim is the better fit for teams building integration-heavy AI workflows, while Dify is the better fit for teams building LLM applications around managed knowledge bases, retrieval, prompts, and app-facing APIs. Both provide visual development and documented self-hosting, but Sim is workflow-first and Dify is LLM-app-first. Compare the current licenses, hosted terms, required integrations, and operational costs against a representative project before choosing. +Sim and Dify overlap as visual platforms for building AI applications, but they are optimized for different jobs: **Sim focuses on AI agents and workflows spanning models, data, and external applications, whereas Dify focuses on building and operating LLM applications with workflows, chatflows, agents, and retrieval.** + +Choose Sim when flexible AI automation, an OSI-approved core license, and broader workflow orchestration are priorities. Choose Dify when the central task is managing retrieval-heavy LLM applications. Neither platform is universally superior. + +_Reviewed September 2026. Product capabilities, hosted pricing, quotas, and license terms should be reconfirmed from the linked first-party sources before purchase or deployment._ ## What is the difference between Sim and Dify? -Sim is an AI workflow and agent platform, whereas Dify is an [LLM application development platform](https://docs.dify.ai/en/cloud/use-dify/getting-started/introduction) with first-party knowledge and RAG features. +**Sim is an AI workflow and agent builder, while Dify is an LLM application development platform with a particularly strong emphasis on application configuration and RAG.** + +[Sim](https://www.sim.ai/) provides a visual workspace for connecting models, agents, knowledge, logic, APIs, and business applications into executable workflows. Its core is available under the standard [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE). -Sim is designed around visual workflows that connect models, agents, tools, data, and external services. That structure suits multi-step automations such as qualifying incoming requests, researching accounts, updating a CRM, drafting content, or routing work for human approval. +[Dify](https://dify.ai/) provides visual workflows and chatflows alongside model-provider management, agents, knowledge bases, retrieval settings, APIs, and application publishing. Its product is organized around the lifecycle of an LLM-powered application. -Dify is designed around building and operating LLM applications. Its [documented product model](https://docs.dify.ai/en/cloud/use-dify/getting-started/introduction) includes application orchestration, model management, observability, and retrieval-augmented generation. That structure suits chatbots, knowledge assistants, text generators, and other applications that need managed retrieval and a stable interface for end users or developers. +The products overlap, but their centers of gravity differ: -Neither product is limited to one category. Sim can implement RAG inside a broader workflow, and Dify can orchestrate multi-step processes. The distinction is the center of gravity: Sim is workflow-first, while Dify is LLM-app-first. +- **Choose Sim** when AI is part of a multi-step process involving external systems, branching logic, data, human-facing tools, or multiple model calls. +- **Choose Dify** when the primary deliverable is a chatbot, assistant, agent, or other LLM application backed by centrally managed prompts and knowledge. ## What are the key facts about Sim, Dify, and n8n? -Sim, Dify, and n8n overlap in visual automation, but their licenses and primary product models differ. +**Sim, Dify, and n8n differ most clearly in license, deployment model, and the type of workflow each platform treats as its primary use case.** -- **Sim:** Sim is an AI workflow and agent builder whose core is released under the OSI-approved [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE); enterprise features are covered by a separate [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE). Sim offers hosted and [self-hosted deployment paths](https://docs.sim.ai/platform/self-hosting). -- **Dify:** As of September 2026, Dify publishes its source code under Apache License 2.0 with [additional conditions described in its repository license](https://github.com/langgenius/dify/blob/main/LICENSE), so buyers should review those conditions rather than treating Dify as unmodified Apache 2.0 software. -- **n8n:** As of September 2026, n8n uses the [Sustainable Use License and Enterprise License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/); these are fair-code, source-available licenses rather than OSI-approved open-source licenses and restrict some commercial uses. +- **Sim:** Sim core uses the OSI-approved [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE), supports [Docker and Kubernetes self-hosting](https://docs.sim.ai/platform/self-hosting), and offers a hosted service whose current plans and usage charges are listed on the [official Sim pricing page](https://www.sim.ai/pricing). Enterprise features in the repository's `ee` directory use a separate [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE). +- **Dify:** Dify supports [self-hosting](https://docs.dify.ai/en/self-host/deploy/overview) under the [Dify Open Source License](https://github.com/langgenius/dify/blob/main/LICENSE) and offers hosted workspace plans with quotas and limits on the [official Dify pricing page](https://dify.ai/pricing). +- **n8n:** n8n supports self-hosting under its source-available [Sustainable Use License and Enterprise License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) and sells hosted plans using the units and limits on the [official n8n pricing page](https://n8n.io/pricing/). -For more context on license categories, see [Apache 2.0 vs fair-code](https://www.sim.ai/library/apache-2-0-vs-fair-code). +As of September 2026, Sim's core uses Apache 2.0, which appears on the [OSI Approved Licenses list](https://opensource.org/licenses). Dify's repository uses a modified license with additional conditions, and n8n's Sustainable Use License is source-available rather than OSI-approved open source. For more context, see [Apache 2.0 vs fair-code](https://www.sim.ai/library/apache-2-0-vs-fair-code). ## How do Sim and Dify compare at a glance? -Sim leads with flexible agentic workflow automation, while Dify leads with an integrated LLM application and knowledge-base experience. +**Sim is usually the better match for cross-application AI workflows, while Dify is usually the better match for teams operating LLM applications and managed retrieval.** -| Buyer question | Sim | Dify | Better fit | +| Buyer criterion | Sim | Dify | Better fit when… | |---|---|---|---| -| What is the product built around? | Visual AI agents and multi-step workflows | [LLM applications, workflows, knowledge, retrieval, and APIs](https://docs.dify.ai/en/cloud/use-dify/getting-started/introduction) | Sim for workflow automation; Dify for app-centric LLM development | -| How are workflows built? | Canvas-based blocks connecting models, tools, logic, data, and integrations | [Visual orchestration within Dify applications](https://docs.dify.ai/en/cloud/use-dify/build/workflow-chatflow) | Sim for cross-system processes; Dify for application-specific orchestration | -| How is RAG handled? | Retrieval can be composed as part of a larger workflow | [Knowledge bases, retrieval configuration, and application grounding](https://docs.dify.ai/en/api-reference/guides/knowledge) are central product concepts | Dify for a packaged RAG experience; Sim for customizable retrieval pipelines | -| What deployment paths are available? | Hosted service and Apache 2.0 self-hosting | Hosted service and [documented self-hosting](https://docs.dify.ai/en/self-host/deploy/overview) | Both, subject to each product’s license and operational requirements | -| How do integrations work? | Workflow connectors, APIs, webhooks, and tool blocks | [Plugins, model providers, APIs, tools, and extensions](https://docs.dify.ai/en/cloud/use-dify/workspace/plugins) | Sim for business-system workflows; Dify for LLM-app components | -| What is the license? | Apache License 2.0 for the core; [separate license](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE) for enterprise features | [Apache License 2.0 with additional repository conditions](https://github.com/langgenius/dify/blob/main/LICENSE) as of September 2026 | Sim for teams requiring standard Apache 2.0 terms | -| Who is it best for? | Automation teams, AI operations teams, and developers coordinating work across systems | AI product teams building chat, assistant, generation, or knowledge applications | Depends on the primary product being built | -| How should pricing be checked? | Confirm current hosted terms on Sim’s official pricing page; Apache 2.0 self-hosting has no software license fee | Confirm current hosted terms on Dify’s official pricing page and self-hosting terms in its repository | Compare current usage, infrastructure, support, and operational costs | +| Primary focus | Visual AI agents and workflows | [LLM applications, chatflows, workflows, agents, and RAG](https://docs.dify.ai/en/learn/key-concepts) | The required outcome determines the fit | +| Workflow building | Coordinates models, logic, data, APIs, and external applications | [Coordinates application steps, tools, retrieval, and outputs](https://docs.dify.ai/en/cloud/use-dify/build/workflow-chatflow) | Sim for broader automation; Dify for app-centric orchestration | +| RAG | Knowledge and retrieval can be incorporated into larger workflows | [Knowledge-base ingestion and retrieval](https://docs.dify.ai/en/api-reference/guides/knowledge) are central platform capabilities | Dify for a RAG-centered product; Sim for RAG inside broader automation | +| Integrations | Emphasizes workflow connections to models and business systems | Emphasizes [model providers, tools, APIs, data sources, and plugins](https://docs.dify.ai/en/cloud/use-dify/workspace/plugins) | Compare the current catalogs against required systems | +| Self-hosting | [Supported](https://docs.sim.ai/platform/self-hosting) | [Supported, including Docker Compose](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) | Both can fit self-hosting requirements | +| License | Apache License 2.0 for core; separate enterprise-feature license | Dify Open Source License with additional conditions | Sim when an OSI-approved core license is required | +| Hosted service | Available | Available | Compare current quotas, usage units, and support requirements | +| Typical team | Automation, operations, product, and engineering teams building AI workflows | Product and AI teams building LLM applications and knowledge assistants | Match the platform to the team's main operating model | +| General automation alternative | More AI-native than a conventional automation platform | More LLM-app-centric than a conventional automation platform | Consider n8n when broad non-AI app automation dominates | -The linked license, deployment, and pricing sources in this article substantiate the factual entries in the table. Buyers comparing more products can also review [open-source AI agent platforms](https://www.sim.ai/library/open-source-ai-agent-platforms). +## Which is better for visual workflow building, Sim or Dify? -## Which is better for building AI workflows, Sim or Dify? +**Sim is generally the more direct choice for visually automating an end-to-end process across AI models and external applications, while Dify is generally the more direct choice for visually composing an LLM application.** -Sim is generally the better fit for AI workflows that coordinate models, tools, business applications, branching logic, and human decisions. +A Sim workflow can represent a broader operational process: receive or fetch data, retrieve context, invoke one or more models, apply logic, call external services, and deliver the result. This makes Sim suitable when the AI step is part of a larger automation rather than the entire product. -Sim’s canvas treats the full process as the product. A team can connect model calls with APIs, webhooks, data operations, conditional paths, and other actions without forcing every automation into the shape of a chatbot or standalone LLM application. +Dify's documented [Workflow and Chatflow builder](https://docs.dify.ai/en/cloud/use-dify/build/workflow-chatflow) combines models, tools, logic, retrieval, conditions, and outputs in applications that can be published through the web or APIs. -Dify also provides [visual workflow orchestration](https://docs.dify.ai/en/cloud/use-dify/build/workflow-chatflow), and it can be the more coherent choice when the workflow exists primarily to power a Dify application. For example, a customer-facing assistant that retrieves documentation, evaluates a question, generates an answer, and exposes the result through an application API fits Dify’s application model well. - -Choose Sim when the workflow must span several operational systems. Choose Dify when the workflow is principally the internal logic of an LLM application. +Neither approach is inherently better. The important architectural question is whether the team is primarily automating a process or operating an LLM application. ## Which is better for RAG, Sim or Dify? -Dify is generally the faster fit for teams that want knowledge ingestion and retrieval managed as first-class parts of an LLM application, while Sim is the more flexible fit when retrieval is one stage in a broader automation. +**Dify is often the better fit for a RAG-centered application, while Sim is often the better fit when retrieval is one component of a larger AI workflow.** -Dify places knowledge bases, document processing, retrieval configuration, and application grounding in one product model. Its [Knowledge API documentation](https://docs.dify.ai/en/api-reference/guides/knowledge) covers managing and querying knowledge bases for search or RAG. That can reduce the amount of architecture a team must assemble for a conventional support assistant, internal knowledge bot, or documentation search application. +Dify gives knowledge management a prominent role in the product. Teams can create knowledge bases, connect them to applications, configure chunking and retrieval, and manage the resulting experience in the same platform, as described in the [official Dify knowledge documentation](https://docs.dify.ai/en/cloud/use-dify/knowledge/create-knowledge/introduction). -Sim lets teams compose retrieval with the rest of a workflow. That approach is useful when documents must be collected from several systems, transformed, classified, searched, checked, and then used to trigger downstream actions. It also lets a team choose the data and retrieval components appropriate to its architecture rather than centering the entire project on a built-in knowledge base. +Sim supports knowledge and retrieval within visual workflows, allowing retrieved context to be combined with model calls, application actions, conditions, and additional processing. Buyers can review the [Sim retrieval documentation](https://docs.sim.ai/knowledgebase/debugging-retrieval). -Dify is the clearer choice for packaged, app-centric RAG. Sim is the clearer choice for customizable RAG pipelines embedded in operational workflows. +For a support assistant whose defining feature is answering from an internal corpus, Dify's application-and-knowledge orientation may reduce conceptual overhead. For a process that retrieves information and then updates systems, requests approval, generates assets, or triggers downstream actions, Sim's broader workflow orientation may be more natural. -## Which is easier to self-host, Sim or Dify? +RAG quality still depends on document preparation, chunking, embedding choices, retrieval settings, reranking, model behavior, evaluation, and source freshness. A platform cannot remove the need to test those components against real queries. -Sim and Dify both document self-hosting, but the easier deployment depends on the team’s license requirements, infrastructure skills, scale, and need for operational support. +## Can Sim and Dify be self-hosted? -Sim’s standard [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE) gives teams broad rights to use, modify, and distribute Sim core under the license terms. Enterprise features in the `ee` directory are excluded and fall under the [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE), which requires an Enterprise subscription for production use and prohibits modification and redistribution. This is important for organizations that require an OSI-approved license or expect to make substantial internal modifications. Sim documents [Docker and Kubernetes self-hosting](https://docs.sim.ai/platform/self-hosting). +**Sim and Dify can both be self-hosted, but their license terms and operational requirements differ.** -Dify provides a self-hosted Community deployment path, including a documented [Docker Compose installation](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose). As of September 2026, its [repository license](https://github.com/langgenius/dify/blob/main/LICENSE) adds conditions to Apache 2.0, so legal and procurement teams should review the actual license before adopting or redistributing the software. +Sim's core source code is available in the [official Sim GitHub repository](https://github.com/simstudioai/sim) under [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE). Apache 2.0 permits use, modification, and distribution subject to its terms and includes an express patent grant. Enterprise features in the `ee` directory are covered by the separate [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE). -Self-hosting either product transfers responsibility for infrastructure, upgrades, secrets, model credentials, databases, monitoring, backups, and security controls to the deploying organization. A source-available repository does not make those operational costs disappear. +Dify's source code is available in the [official Dify GitHub repository](https://github.com/langgenius/dify). Dify documents self-hosting through [Docker Compose](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose), but buyers should read the repository's [current license](https://github.com/langgenius/dify/blob/main/LICENSE) because it adds conditions to Apache 2.0. -## Which has better integrations, Sim or Dify? +Self-hosting either product still requires operational ownership. Teams should plan for secrets, model credentials, databases, storage, networking, access controls, backups, observability, upgrades, and incident response. -Sim is better aligned with cross-application automation, while Dify is better aligned with the model, retrieval, plugin, and API components of an LLM application. +## Is Sim open source, and is Dify open source? -Raw integration counts are not a reliable way to compare the products because vendors classify models, tools, triggers, community packages, and native connectors differently. Buyers should instead test the exact systems required by the intended workflow. +**Sim core is open source under Apache License 2.0, while Dify is source-available under a modified license that adds conditions beyond standard Apache 2.0.** -For Sim, verify that the necessary workflow triggers, actions, APIs, authentication methods, and data transformations are available. For Dify, verify the necessary model providers, knowledge sources, tools, plugins, APIs, and application interfaces described in its [current tools documentation](https://docs.dify.ai/en/cloud/use-dify/workspace/tools). +This distinction matters when procurement or engineering policy requires an OSI-approved license. Sim's [LICENSE file](https://github.com/simstudioai/sim/blob/main/LICENSE) contains the standard Apache 2.0 terms, while enterprise features carry a [separate license](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE). -If a required connector is missing, compare whether the platform can call the service through HTTP, a webhook, custom code, or an extension mechanism. That fallback often matters more than the published integration count. For background on one extension standard, read [what an MCP server is](https://www.sim.ai/library/what-is-an-mcp-server). +Dify describes its terms in its [official LICENSE file](https://github.com/langgenius/dify/blob/main/LICENSE). Organizations considering Dify should review the additional conditions, especially if they plan to provide a multi-tenant service, alter branding, redistribute the software, or embed it in a commercial offering. -## Which is better for teams, Sim or Dify? +This article does not provide legal advice. Teams with commercial redistribution or hosted-service plans should have counsel evaluate the current license text. Buyers comparing licensing across the category can also review [open-source AI agent platforms](https://www.sim.ai/library/open-source-ai-agent-platforms). -Sim is better suited to teams that think in automations and operational processes, while Dify is better suited to teams that think in LLM applications, knowledge bases, and product APIs. +## Which has more integrations, Sim or Dify? -Sim is likely to fit automation engineers, AI operations teams, growth teams, and developers who need to coordinate actions across multiple services. Its visual workflow model makes the sequence of operational steps the primary artifact. +**Sim is oriented toward integrations used in complete AI-powered business workflows, while Dify is oriented toward the models, tools, plugins, APIs, and data sources used by LLM applications.** -Dify is likely to fit AI product teams, application developers, and knowledge-management teams shipping assistants or generation features. Its [application publishing model](https://docs.dify.ai/en/cloud/use-dify/publish/README) groups workflows, models, retrieval, APIs, and observability around an LLM experience. +Raw integration counts are a weak buying metric because vendors classify models, triggers, actions, community plugins, and generic HTTP connections differently. A better evaluation is to test the exact systems required by the proposed workflow. -Mixed teams should prototype one representative use case in each platform. The test should include the real data source, model, authentication flow, approval step, failure path, and deployment environment rather than a simplified demonstration. +For Sim, verify whether each required service has the necessary trigger, action, authentication method, and data fields in the [current Sim documentation](https://docs.sim.ai/). For Dify, inspect the [current Dify integrations documentation](https://docs.dify.ai/en/cloud/use-dify/workspace/plugins) from the perspective of the target LLM application. -## How does n8n compare with Sim and Dify? +Both products can use APIs to reach services without a dedicated connector, but a generic API call may require more setup and maintenance than a maintained native integration. -n8n is the incumbent to evaluate when conventional application automation is as important as AI orchestration. +## How much do Sim and Dify cost? -n8n describes itself as a [workflow automation tool combining AI features with business process automation](https://docs.n8n.io/), making it relevant for buyers comparing Sim with established automation platforms. Sim is more directly centered on AI agents and model-driven workflows. Dify is more directly centered on LLM applications and managed knowledge. +**Sim and Dify costs depend on hosted plan limits, model usage, storage, execution volume, and whether the team self-hosts.** -The licensing distinction is material. As of September 2026, n8n’s [Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) is fair-code and source-available rather than OSI-approved, while Sim uses the OSI-approved [Apache License 2.0](https://github.com/simstudioai/sim/blob/main/LICENSE). Organizations that plan to self-host, modify, redistribute, or offer workflows as part of a commercial service should review the applicable licenses rather than relying on the word “open.” +As of September 2026, current hosted prices and included quotas should be taken directly from the [Sim pricing page](https://www.sim.ai/pricing) and [Dify pricing page](https://dify.ai/pricing). Exact numeric prices are not reproduced here because plan prices and allowances can change independently of this comparison. -Choose n8n when a mature general automation ecosystem is the primary requirement. Choose Sim when AI-native workflow composition and Apache 2.0 licensing are priorities. Choose Dify when the primary deliverable is an LLM application with integrated knowledge and retrieval. +A useful total-cost comparison should include: -## How much do Sim and Dify cost? +1. Hosted workspace or subscription charges. +2. Model-provider token or inference charges. +3. Workflow or message usage beyond included allowances. +4. Vector storage, databases, files, and network transfer. +5. Engineering time for custom integrations and evaluation. +6. Infrastructure and operational labor for self-hosting. +7. Security, support, governance, and compliance requirements. + +Self-hosted software is not cost-free. Sim core does not require a software license fee for use under Apache 2.0, but infrastructure and connected services still cost money. Dify self-hosting similarly creates infrastructure and operations costs and remains subject to the Dify Open Source License. + +## Which is better for teams, Sim or Dify? + +**Sim fits teams automating AI-driven processes across systems, while Dify fits teams building and managing LLM applications as products or internal services.** + +Choose Sim when the team includes automation engineers, operations specialists, product builders, or developers who need to see and modify a complete AI workflow. Sim's Apache 2.0 core license is also relevant for organizations with strict open-source or extensibility requirements. + +Choose Dify when the team wants a centralized environment for configuring model providers, retrieval, tools, and application behavior. Dify can be particularly suitable for teams repeatedly launching assistants or other knowledge-backed LLM interfaces. + +For either platform, test collaboration and governance against real requirements rather than feature labels. Important questions include role-based access, environment separation, versioning, approval processes, secret management, logs, evaluation, and rollback procedures. -Sim and Dify should be compared using their official pricing pages because this article does not preserve exact hosted prices that may become stale. +## How do Sim and Dify compare with n8n? -As of September 2026, buyers should verify [Sim’s current hosted pricing](https://www.sim.ai/pricing) and [Dify’s current hosted pricing](https://dify.ai/pricing). Compare the billing unit, included usage, model costs, storage, seats, execution limits, support, and overage policy for the intended workload. +**Sim is the AI-native workflow option, Dify is the LLM-application option, and n8n is the general-purpose automation option.** -For self-hosting, include infrastructure, database, observability, backup, upgrade, security, and engineering costs. Sim’s [Apache 2.0 software](https://github.com/simstudioai/sim/blob/main/LICENSE) can be self-hosted without a software license fee under that license, but operating it still consumes infrastructure and staff time. Dify adopters should review the repository’s [current additional license conditions](https://github.com/langgenius/dify/blob/main/LICENSE) alongside the technical costs. +[n8n](https://n8n.io/) is relevant because many buyers begin with application automation and then add AI. Its [official documentation](https://docs.n8n.io/) describes a fair-code workflow automation tool combining AI capabilities with business process automation, which can make it a fit when most steps move data between applications and only some steps use models. -## When should you choose Sim instead of Dify? +Sim is more directly centered on building AI agents and model-driven workflows in a visual workspace. Dify is more directly centered on creating and operating LLM applications with retrieval and tools. -Sim is the stronger fit when the main requirement is an AI-driven workflow that crosses multiple tools, data sources, and operational steps. +Licensing also differs. As of September 2026, n8n uses its [Sustainable Use License and Enterprise License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/). These are fair-code licenses rather than OSI-approved open-source licenses. Sim core uses Apache 2.0, while Dify uses its own modified license. -Choose Sim when: +A simple decision rule is: -- The primary artifact is a workflow rather than a chatbot or LLM application. -- Agents must take actions across business systems. -- Retrieval is one component in a larger pipeline. -- The team requires the standard Apache License 2.0. -- The workflow needs branching, approvals, API calls, and downstream automation. -- The team wants the same workflow architecture available through hosted or self-hosted deployment. +- Choose **n8n** when broad, conventional application automation is the dominant need. +- Choose **Dify** when a managed LLM application or RAG experience is the dominant need. +- Choose **Sim** when AI agents and model-driven processes must coordinate knowledge, logic, and external systems under an OSI-approved core license. -Sim’s advantage in these cases is fit, not universal superiority. Teams focused on managed knowledge applications may reach production faster with Dify. +## Is Sim better than Dify? -## When should you choose Dify instead of Sim? +**Sim is better suited to cross-application AI automation and Apache 2.0 core self-hosting, while Dify is better suited to teams whose primary unit of work is an LLM application.** -Dify is the stronger fit when the main requirement is an [LLM application with integrated workflows, knowledge, retrieval, APIs, and runtime management](https://docs.dify.ai/en/cloud/use-dify/knowledge/readme). +Sim's strongest case is not an unsupported claim of universal superiority. Its advantage is the combination of visual AI workflow building, external-system orchestration, self-hosting, and a standard open-source core license. -Choose Dify when: +Dify's strongest case is its cohesive environment for models, application workflows, knowledge bases, retrieval, and LLM application delivery. Teams should favor Dify when those capabilities align more closely with the system they are building. -- The primary deliverable is a chatbot, assistant, generator, or other LLM application. -- The team wants knowledge bases and retrieval managed inside the same platform. -- Application APIs and app-specific monitoring are central requirements. -- Product developers want one environment for model configuration, prompts, retrieval, and deployment. -- The workflow mainly exists to support a Dify application. +A proof of concept should use the same documents, models, external systems, security requirements, and success criteria planned for production. Compare build time, answer quality, observability, failure recovery, deployment effort, and total cost rather than relying on a generic feature checklist. -Dify’s advantage in these cases is product coherence. Teams should still review its current [repository license conditions](https://github.com/langgenius/dify/blob/main/LICENSE) and confirm that required integrations and deployment controls meet their policies. +## What should I test before choosing Sim or Dify? -## What is the final verdict on Sim vs Dify? +**Sim and Dify should be tested with one representative production workflow before either platform is selected.** -Sim is the better choice for integration-heavy AI workflows, while Dify is the better choice for app-centric RAG and LLM product development. +Use the following evaluation checklist: -Use Sim when agents must coordinate work across tools and when Apache 2.0 licensing matters. Use Dify when the shortest path to a knowledge-grounded assistant or LLM application matters more than using a general workflow canvas. +1. Build the same high-value workflow in both products. +2. Connect the actual model providers, knowledge sources, and business applications required in production. +3. Measure retrieval relevance and answer grounding with a fixed evaluation set. +4. Test malformed inputs, unavailable APIs, model timeouts, and partial failures. +5. Inspect logs and determine whether operators can diagnose each failed step. +6. Confirm authentication, secret storage, access controls, and data retention. +7. Reproduce the intended cloud or self-hosted deployment. +8. Calculate model, platform, infrastructure, and labor costs at expected volume. +9. Review Sim's Apache 2.0 core license, its enterprise-feature license, and Dify's current license against the intended use. +10. Ask the people who will maintain the system to modify and debug the workflow. -Teams still deciding among the broader market should consult [The Best AI Agent Builders in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026), which is Sim’s canonical guide to the “best AI agent builder” question. This page owns the narrower Sim-versus-Dify decision rather than making a universal head-term ranking claim. +The better product is the one that satisfies the real deployment and operating constraints with the least avoidable complexity. -## Which official sources support this comparison? +For a broader category comparison, see [Best AI Agent Builder in 2026](https://www.sim.ai/library/best-ai-agent-builder-2026); this page remains focused on the Sim-versus-Dify decision. -Sim, Dify, and n8n publish the primary documentation and license texts buyers should review before making a final decision. +## Where can I verify the claims in this comparison? + +**Sim, Dify, and n8n publish the primary documentation, repositories, licenses, deployment instructions, and pricing pages needed to verify this comparison.** + +Primary sources: - [Sim website](https://www.sim.ai/) -- [Sim pricing](https://www.sim.ai/pricing) -- [Sim source repository and Apache 2.0 license](https://github.com/simstudioai/sim/blob/main/LICENSE) +- [Sim documentation](https://docs.sim.ai/) +- [Sim GitHub repository](https://github.com/simstudioai/sim) +- [Sim Apache 2.0 license](https://github.com/simstudioai/sim/blob/main/LICENSE) - [Sim Enterprise License](https://github.com/simstudioai/sim/blob/main/apps/sim/ee/LICENSE) - [Sim self-hosting documentation](https://docs.sim.ai/platform/self-hosting) -- [Dify documentation](https://docs.dify.ai/en/home) +- [Sim pricing](https://www.sim.ai/pricing) +- [Dify website](https://dify.ai/) +- [Dify documentation](https://docs.dify.ai/en/learn/key-concepts) +- [Dify GitHub repository](https://github.com/langgenius/dify) +- [Dify license](https://github.com/langgenius/dify/blob/main/LICENSE) +- [Dify self-hosting documentation](https://docs.dify.ai/en/self-host/deploy/quick-start/docker-compose) - [Dify pricing](https://dify.ai/pricing) -- [Dify source repository and license](https://github.com/langgenius/dify/blob/main/LICENSE) -- [Dify self-hosting documentation](https://docs.dify.ai/en/self-host/deploy/overview) -- [n8n Sustainable Use License](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) -- [n8n source repository](https://github.com/n8n-io/n8n) +- [n8n license documentation](https://docs.n8n.io/privacy-and-security/sustainable-use-license/) +- [n8n pricing](https://n8n.io/pricing/) diff --git a/apps/sim/ee/access-control/components/group-detail.test.tsx b/apps/sim/ee/access-control/components/group-detail.test.tsx new file mode 100644 index 00000000000..3ca858c2a35 --- /dev/null +++ b/apps/sim/ee/access-control/components/group-detail.test.tsx @@ -0,0 +1,161 @@ +/** @vitest-environment jsdom */ + +import { act, type ReactNode } from 'react' +import { createDeferred } from '@sim/testing/helpers/deferred' +import { jsonResponse } from '@sim/testing/helpers/http' +import { authClientMock } from '@sim/testing/mocks/auth-client.mock' +import { nextNavigationMock } from '@sim/testing/mocks/next-navigation.mock' +import { providersModelsMock } from '@sim/testing/mocks/providers-models.mock' +import { providersUtilsMock, providersUtilsMockFns } from '@sim/testing/mocks/providers-utils.mock' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { NuqsTestingAdapter } from 'nuqs/adapters/testing' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { PermissionGroup } from '@/lib/api/contracts/permission-groups' +import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' +import { GroupDetail } from '@/ee/access-control/components/group-detail' +import { organizationKeys } from '@/hooks/queries/utils/organization-keys' +import { permissionGroupKeys } from '@/hooks/queries/utils/permission-group-keys' + +vi.mock('@/lib/auth/auth-client', () => authClientMock) +vi.mock('next/navigation', () => nextNavigationMock) +vi.mock('@/providers/models', () => providersModelsMock) +vi.mock('@/providers/utils', () => providersUtilsMock) +vi.mock('@/app/workspace/[workspaceId]/settings/components/settings-panel', () => ({ + SettingsPanel: ({ children }: { children: ReactNode }) => <>{children}, +})) + +const group: PermissionGroup = { + id: 'group-1', + name: 'Engineering', + description: null, + config: { ...DEFAULT_PERMISSION_GROUP_CONFIG }, + createdBy: 'user-1', + createdAt: '2026-01-01T00:00:00Z', + updatedAt: '2026-01-01T00:00:00Z', + creatorName: null, + creatorEmail: null, + memberCount: 0, + isDefault: false, + workspaces: [], +} + +let root: Root +let container: HTMLDivElement +let client: QueryClient + +beforeEach(() => { + vi.useFakeTimers() + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + providersUtilsMockFns.mockGetAllProviderIds.mockReturnValue(['openai', 'anthropic']) + client = new QueryClient({ defaultOptions: { queries: { retry: false } } }) + client.setQueryData(permissionGroupKeys.members('org-1', 'group-1'), []) + client.setQueryData(organizationKeys.roster('org-1'), { + members: [], + pendingInvitations: [], + workspaces: [], + }) + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) +}) + +afterEach(() => { + act(() => root.unmount()) + client.clear() + container.remove() + providersUtilsMockFns.mockGetAllProviderIds.mockReset() + vi.useRealTimers() +}) + +function render() { + act(() => + root.render( + + + {}} + onDeleted={() => {}} + /> + + + ) + ) +} + +function expectNoProviderControls() { + expect(container.querySelector('[id^="provider-"]')).toBeNull() + expect(container.querySelector('input[placeholder="Search providers..."]')).toBeNull() + expect( + [...container.querySelectorAll('button')].some((button) => + /^(De)?select All$/i.test(button.textContent ?? '') + ) + ).toBe(false) +} + +async function settle() { + await act(async () => { + await vi.advanceTimersByTimeAsync(1) + }) +} + +describe('provider permission policy availability', () => { + it('withholds provider edits until the server policy is known', () => { + vi.stubGlobal( + 'fetch', + vi.fn(() => createDeferred().promise) + ) + render() + expectNoProviderControls() + }) + + it.each([ + { status: 503, body: { error: 'Policy temporarily unavailable' }, blacklist: ['openai'] }, + { status: 401, body: { error: 'Session expired' }, blacklist: [] }, + { status: 200, body: { blacklistedProviders: 'invalid' }, blacklist: ['openai'] }, + ])( + 'withholds edits after a $status response and recovers through retry', + async ({ status, body, blacklist }) => { + const retry = createDeferred() + let requests = 0 + vi.stubGlobal( + 'fetch', + vi.fn((url: string) => { + if (url !== '/api/settings/allowed-providers') + throw new Error(`Unexpected request: ${url}`) + requests++ + return requests === 1 ? Promise.resolve(jsonResponse(body, status)) : retry.promise + }) + ) + render() + await settle() + expect(container.querySelector('[role="alert"]')).not.toBeNull() + expectNoProviderControls() + const retryButton = [...container.querySelectorAll('button')].find( + (button) => button.textContent === 'Try again' + ) + expect(retryButton).toBeDefined() + act(() => retryButton!.click()) + await settle() + expect(requests).toBe(2) + expectNoProviderControls() + await act(async () => { + retry.resolve(jsonResponse({ blacklistedProviders: blacklist })) + }) + await settle() + expect(container.querySelector('[role="alert"]')).toBeNull() + const anthropic = container.querySelector('#provider-anthropic') + expect(anthropic?.getAttribute('aria-checked')).toBe('true') + expect(Boolean(container.querySelector('#provider-openai'))).toBe( + !blacklist.includes('openai') + ) + act(() => anthropic!.click()) + expect(anthropic?.getAttribute('aria-checked')).toBe('false') + } + ) +}) diff --git a/apps/sim/ee/access-control/components/group-detail.tsx b/apps/sim/ee/access-control/components/group-detail.tsx index 52230d0ba2e..16e819069bd 100644 --- a/apps/sim/ee/access-control/components/group-detail.tsx +++ b/apps/sim/ee/access-control/components/group-detail.tsx @@ -50,7 +50,10 @@ import { } from '@/app/workspace/[workspaceId]/settings/[section]/search-params' import { MemberRow } from '@/app/workspace/[workspaceId]/settings/components/member-list' import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' -import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { + SettingsEmptyState, + SettingsQueryErrorState, +} from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel' import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' import { useSettingsUnsavedGuard } from '@/app/workspace/[workspaceId]/settings/hooks/use-settings-unsaved-guard' @@ -775,7 +778,7 @@ export function GroupDetail({ viewingGroup.id ) const { data: roster } = useOrganizationRoster(organizationId) - const { data: blacklistedProvidersData } = useBlacklistedProviders({ enabled: true }) + const blacklistedProviders = useBlacklistedProviders() // Recompute when custom (deploy-as-block) blocks or the viewer's block // visibility hydrate into the overlay. @@ -815,11 +818,10 @@ export function GroupDetail({ const visibleBlocks = useMemo(() => allBlocks.filter((b) => !b.hideFromToolbar), [allBlocks]) const allProviderIds = useMemo(() => { - const allIds = getAllProviderIds() - const blacklist = blacklistedProvidersData?.blacklistedProviders ?? [] - if (blacklist.length === 0) return allIds - return allIds.filter((id) => !blacklist.includes(id.toLowerCase())) - }, [blacklistedProvidersData]) + if (!blacklistedProviders.isSuccess) return [] + const blacklist = blacklistedProviders.data.blacklistedProviders + return getAllProviderIds().filter((id) => !blacklist.includes(id.toLowerCase())) + }, [blacklistedProviders.data, blacklistedProviders.isSuccess]) /** Maps every tool id to ALL block types that expose it (some tools are shared across blocks). */ const toolBlockTypes = useMemo(() => { @@ -1616,50 +1618,63 @@ export function GroupDetail({ )} - {configTab === 'providers' && ( -
-
- setSearchTerm(e.target.value)} - className='min-w-0 flex-1' - /> - void setStatusFilter(next)} - /> - setProvidersAllowed(filteredProviders, !filteredProvidersAllAllowed)} - disabled={filteredProviders.length === 0} - > - {filteredProvidersAllAllowed ? 'Deselect All' : 'Select All'} - -
- {filteredProviders.length === 0 ? ( - - No providers match your filters. - - ) : ( -
- {filteredProviders.map((providerId) => ( - toggleProvider(providerId)} - deniedCount={deniedCountByProvider[providerId] ?? 0} - workspaceId={workspaceId} - isAllowed={isModelAllowed} - onToggle={toggleModel} - onSetDenied={setModelsDenied} - /> - ))} + {configTab === 'providers' && + (blacklistedProviders.isError ? ( + void blacklistedProviders.refetch()} + variant='inline' + /> + ) : !blacklistedProviders.isSuccess ? ( + Loading providers + ) : ( +
+
+ setSearchTerm(e.target.value)} + className='min-w-0 flex-1' + /> + void setStatusFilter(next)} + /> + + setProvidersAllowed(filteredProviders, !filteredProvidersAllAllowed) + } + disabled={filteredProviders.length === 0} + > + {filteredProvidersAllAllowed ? 'Deselect All' : 'Select All'} +
- )} -
- )} + {filteredProviders.length === 0 ? ( + + No providers match your filters. + + ) : ( +
+ {filteredProviders.map((providerId) => ( + toggleProvider(providerId)} + deniedCount={deniedCountByProvider[providerId] ?? 0} + workspaceId={workspaceId} + isAllowed={isModelAllowed} + onToggle={toggleModel} + onSetDenied={setModelsDenied} + /> + ))} +
+ )} +
+ ))} {configTab === 'blocks' && (
diff --git a/apps/sim/ee/credential-groups/components/credential-group-access.tsx b/apps/sim/ee/credential-groups/components/credential-group-access.tsx deleted file mode 100644 index cf524f5e196..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-access.tsx +++ /dev/null @@ -1,290 +0,0 @@ -'use client' - -import { useState } from 'react' -import { Chip, toast } from '@sim/emcn' -import { Workflow } from '@sim/emcn/icons' -import { getErrorMessage } from '@sim/utils/errors' -import type { CredentialGroupAccessResponse } from '@/lib/api/contracts/credential-groups' -import { CREDENTIAL_GROUP_WORKFLOW_ACCESS_LIMIT } from '@/lib/credential-groups/limits' -import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' -import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import { - RESOURCE_LIST_STACK, - SettingsResourceRow, -} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' -import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' -import { CredentialGroupAddResourceModal } from '@/ee/credential-groups/components/credential-group-add-resource-modal' -import { - useCredentialGroupAccess, - useUpdateCredentialGroupAccess, -} from '@/hooks/queries/credential-groups' -import { useSettingsDirtyStore } from '@/stores/settings/dirty/store' - -interface AccessDraft { - allowedWorkflowIds: string[] - baseline: string - expectedRevision: number - groupId: string -} - -interface UseCredentialGroupAccessEditorProps { - workspaceId: string - groupId: string - enabled: boolean -} - -function normalizeAllowedWorkflowIds(workflowIds: readonly string[]): string[] { - for (const workflowId of workflowIds) { - if (!workflowId || workflowId !== workflowId.trim()) { - throw new Error('Credential Group workflow access requires canonical non-empty workflow IDs') - } - } - if (new Set(workflowIds).size !== workflowIds.length) { - throw new Error('Credential Group workflow access contains duplicate workflows') - } - if (workflowIds.length > CREDENTIAL_GROUP_WORKFLOW_ACCESS_LIMIT) { - throw new Error( - `Credential Group workflow access cannot exceed ${CREDENTIAL_GROUP_WORKFLOW_ACCESS_LIMIT} workflows` - ) - } - return [...workflowIds].sort() -} - -function serializeAllowedWorkflowIds(workflowIds: readonly string[]): string { - return JSON.stringify(normalizeAllowedWorkflowIds(workflowIds)) -} - -export function useCredentialGroupAccessEditor({ - workspaceId, - groupId, - enabled, -}: UseCredentialGroupAccessEditorProps) { - const access = useCredentialGroupAccess(workspaceId, groupId, { enabled }) - const updateAccess = useUpdateCredentialGroupAccess() - const setSettingsNavigationBlocked = useSettingsDirtyStore((state) => state.setNavigationBlocked) - const [draft, setDraft] = useState(null) - - if (draft && draft.groupId !== groupId) { - throw new Error('Credential Group access draft cannot move between resources') - } - - const persistedAllowedWorkflowIds = access.data - ? normalizeAllowedWorkflowIds(access.data.allowedWorkflowIds) - : null - const persistedValue = persistedAllowedWorkflowIds - ? serializeAllowedWorkflowIds(persistedAllowedWorkflowIds) - : '' - const allowedWorkflowIds = draft?.allowedWorkflowIds ?? persistedAllowedWorkflowIds - const revision = draft?.expectedRevision ?? access.data?.revision ?? null - const dirty = draft !== null - const workflowIds = new Set(access.data?.workflows.map((workflow) => workflow.id) ?? []) - const selectionsAvailable = Boolean( - allowedWorkflowIds?.every((workflowId) => workflowIds.has(workflowId)) - ) - - const setAllowedWorkflowIds = (nextWorkflowIds: readonly string[], expectedRevision: number) => { - if (!access.data) throw new Error('Credential Group workflow access is unavailable') - const currentRevision = draft?.expectedRevision ?? access.data.revision - if (expectedRevision !== currentRevision) { - throw new Error('Credential Group workflow access changed while it was being edited') - } - const normalizedWorkflowIds = normalizeAllowedWorkflowIds(nextWorkflowIds) - const nextValue = serializeAllowedWorkflowIds(normalizedWorkflowIds) - updateAccess.reset() - setDraft((current) => { - const baseline = current?.baseline ?? persistedValue - if (nextValue === baseline) return null - return { - allowedWorkflowIds: normalizedWorkflowIds, - baseline, - expectedRevision: current?.expectedRevision ?? access.data.revision, - groupId, - } - }) - } - - const discard = () => { - setDraft(null) - updateAccess.reset() - } - - const save = async () => { - if (!draft) return - setSettingsNavigationBlocked(true) - try { - const availableWorkflowIds = new Set(access.data?.workflows.map((workflow) => workflow.id)) - if (draft.allowedWorkflowIds.some((workflowId) => !availableWorkflowIds.has(workflowId))) { - throw new Error('Remove unavailable workflows before saving access') - } - await updateAccess.mutateAsync({ - workspaceId, - groupId, - body: { - expectedRevision: draft.expectedRevision, - allowedWorkflowIds: draft.allowedWorkflowIds, - }, - }) - setDraft(null) - toast.success('Workflow access saved') - } catch (error) { - toast.error(getErrorMessage(error, 'Could not update workflow access')) - } finally { - setSettingsNavigationBlocked(false) - } - } - - return { - allowedWorkflowIds, - revision, - workflows: access.data?.workflows ?? null, - setAllowedWorkflowIds, - discard, - save, - dirty, - error: updateAccess.error - ? getErrorMessage(updateAccess.error, 'Could not update workflow access') - : null, - isPending: access.isPending && !access.data, - loadError: access.data ? null : access.error, - isReady: Boolean(access.data && selectionsAvailable), - saving: updateAccess.isPending, - } -} - -interface CredentialGroupAccessProps { - allowedWorkflowIds: readonly string[] | null - revision: number | null - workflows: CredentialGroupAccessResponse['workflows'] | null - onAllowedWorkflowIdsChange: (workflowIds: readonly string[], expectedRevision: number) => void - error: string | null - isPending: boolean - loadError: unknown - saving: boolean -} - -export function CredentialGroupAccess({ - allowedWorkflowIds, - revision, - workflows, - onAllowedWorkflowIdsChange, - error, - isPending, - loadError, - saving, -}: CredentialGroupAccessProps) { - const [showAddWorkflow, setShowAddWorkflow] = useState(false) - - if (loadError) { - return ( - - {getErrorMessage(loadError, "Couldn't load workflow access")} - - ) - } - if (isPending) return null - if (!workflows) throw new Error('Credential Group workflow catalog is unavailable') - if (!allowedWorkflowIds) throw new Error('Credential Group workflow access is unavailable') - if (revision === null) throw new Error('Credential Group access revision is unavailable') - - const allowedWorkflowIdSet = new Set(allowedWorkflowIds) - if (allowedWorkflowIdSet.size !== allowedWorkflowIds.length) { - throw new Error('Credential Group workflow access contains duplicate workflows') - } - const workflowsById = new Map(workflows.map((workflow) => [workflow.id, workflow])) - for (const workflowId of allowedWorkflowIds) { - if (!workflowsById.has(workflowId)) { - throw new Error( - `Credential Group workflow access references unavailable workflow ${workflowId}` - ) - } - } - const allowedWorkflows = workflows.filter((workflow) => allowedWorkflowIdSet.has(workflow.id)) - const availableWorkflows = workflows.filter((workflow) => !allowedWorkflowIdSet.has(workflow.id)) - - const addWorkflow = (workflowId: string) => { - if (!workflowsById.has(workflowId)) throw new Error(`Workflow ${workflowId} is unavailable`) - if (allowedWorkflowIdSet.has(workflowId)) { - throw new Error(`Workflow ${workflowId} already has Credential Group access`) - } - onAllowedWorkflowIdsChange([...allowedWorkflowIds, workflowId], revision) - } - - const removeWorkflow = (workflowId: string) => { - if (!allowedWorkflowIdSet.has(workflowId)) { - throw new Error(`Workflow ${workflowId} does not have Credential Group access`) - } - onAllowedWorkflowIdsChange( - allowedWorkflowIds.filter((allowedWorkflowId) => allowedWorkflowId !== workflowId), - revision - ) - } - - const sectionAction = ( - setShowAddWorkflow(true)} - disabled={ - saving || - availableWorkflows.length === 0 || - allowedWorkflowIds.length >= CREDENTIAL_GROUP_WORKFLOW_ACCESS_LIMIT - } - > - Add workflow - - ) - - return ( - <> - - {error && ( -

- {error} -

- )} - - {allowedWorkflows.length === 0 ? ( - No workflows have access - ) : ( -
- {allowedWorkflows.map((workflow) => ( - } - iconFilled - title={workflow.name} - description='Deployed runs can use every credential in this group' - disabled={saving} - trailing={ - saving ? undefined : ( - removeWorkflow(workflow.id), - }, - ]} - /> - ) - } - /> - ))} -
- )} -
- - {showAddWorkflow && ( - { - addWorkflow(id) - setShowAddWorkflow(false) - }} - onClose={() => setShowAddWorkflow(false)} - /> - )} - - ) -} diff --git a/apps/sim/ee/credential-groups/components/credential-group-add-resource-modal.tsx b/apps/sim/ee/credential-groups/components/credential-group-add-resource-modal.tsx deleted file mode 100644 index e19d8efba7b..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-add-resource-modal.tsx +++ /dev/null @@ -1,110 +0,0 @@ -'use client' - -import { useState } from 'react' -import { - ChipDropdown, - ChipModal, - ChipModalBody, - ChipModalError, - ChipModalField, - ChipModalFooter, - ChipModalHeader, - ChipSelect, -} from '@sim/emcn' - -interface CredentialGroupAddResourceModalBaseProps { - resources: readonly { id: string; name: string }[] - disabled: boolean - error?: string - onClose: () => void -} - -type CredentialGroupAddResourceModalProps = CredentialGroupAddResourceModalBaseProps & - ( - | { resourceType: 'workflow'; onAdd: (resourceId: string) => void } - | { resourceType: 'workspace'; onAdd: (resourceIds: string[]) => void } - ) - -export function CredentialGroupAddResourceModal(props: CredentialGroupAddResourceModalProps) { - const { resources, resourceType, disabled, error, onClose } = props - const [selectedResourceIds, setSelectedResourceIds] = useState([]) - const label = resourceType === 'workspace' ? 'Workspaces' : 'Workflow' - const title = resourceType === 'workspace' ? 'Add workspaces' : 'Add workflow' - const options = resources.map((resource) => ({ value: resource.id, label: resource.name })) - - const handleAdd = () => { - if (!selectedResourceIds.length) - throw new Error(`Select a ${resourceType} before granting access`) - if (new Set(selectedResourceIds).size !== selectedResourceIds.length) { - throw new Error('Access selection contains duplicate resources') - } - const available = new Set(resources.map((resource) => resource.id)) - for (const id of selectedResourceIds) { - if (!available.has(id)) throw new Error(`Selected ${resourceType} ${id} is unavailable`) - } - if (props.resourceType === 'workspace') props.onAdd(selectedResourceIds) - else props.onAdd(selectedResourceIds[0]) - } - - return ( - !open && !disabled && onClose()} - srTitle={title} - size='sm' - dismissDisabled={disabled} - > - - {title} - - - - {(aria) => - resourceType === 'workspace' ? ( - - ) : ( - setSelectedResourceIds([id])} - placeholder={`Select ${resourceType}`} - searchPlaceholder={`Search ${resourceType}s`} - searchable - aria-label={label} - disabled={disabled} - fullWidth - dropdownWidth='trigger' - align='start' - {...aria} - /> - ) - } - - {error} - - - - ) -} diff --git a/apps/sim/ee/credential-groups/components/credential-group-detail.tsx b/apps/sim/ee/credential-groups/components/credential-group-detail.tsx deleted file mode 100644 index 75bff93c737..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-detail.tsx +++ /dev/null @@ -1,371 +0,0 @@ -'use client' - -import { useState } from 'react' -import { Avatar, Chip, ChipConfirmModal, ChipModalTabs, toast } from '@sim/emcn' -import { Plus } from '@sim/emcn/icons' -import { getErrorMessage } from '@sim/utils/errors' -import { useQueryState } from 'nuqs' -import { saveDiscardActions } from '@/components/settings/save-discard-actions' -import type { CredentialGroupEnrollment } from '@/lib/api/contracts/credential-groups' -import { SLACK_CUSTOM_BOT_PROVIDER_ID } from '@/lib/oauth/types' -import { UnsavedChangesModal } from '@/app/workspace/[workspaceId]/components/credential-detail' -import { - credentialGroupPeopleSearchParam, - credentialGroupPeopleSearchUrlKeys, - credentialGroupProviderSearchParam, - credentialGroupProviderSearchUrlKeys, - credentialGroupTabParam, - credentialGroupTabUrlKeys, -} from '@/app/workspace/[workspaceId]/settings/[section]/search-params' -import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' -import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import type { SettingsAction } from '@/app/workspace/[workspaceId]/settings/components/settings-header/settings-header' -import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel' -import { - RESOURCE_LIST_STACK, - SettingsResourceRow, -} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' -import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' -import { useSettingsUnsavedGuard } from '@/app/workspace/[workspaceId]/settings/hooks/use-settings-unsaved-guard' -import { - CredentialGroupAccess, - useCredentialGroupAccessEditor, -} from '@/ee/credential-groups/components/credential-group-access' -import { CredentialGroupDetails } from '@/ee/credential-groups/components/credential-group-details' -import { EnrollmentConnections } from '@/ee/credential-groups/components/credential-group-enrollment-connections' -import { CredentialGroupInviteModal } from '@/ee/credential-groups/components/credential-group-invite-modal' -import { - useCredentialGroupDetail, - useDeleteCredentialGroupEnrollment, - useResendCredentialGroupEnrollment, - useUpdateCredentialGroup, -} from '@/hooks/queries/credential-groups' -import { useWorkspaceCredentials } from '@/hooks/queries/credentials' -import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter' - -interface CredentialGroupDetailProps { - workspaceId: string - groupId: string -} - -type CredentialGroupTab = 'details' | 'people' | 'access' - -const CREDENTIAL_GROUP_TABS = [ - { value: 'details', label: 'Accounts' }, - { value: 'people', label: 'People' }, - { value: 'access', label: 'Workflow access' }, -] as const - -export function CredentialGroupDetail({ workspaceId, groupId }: CredentialGroupDetailProps) { - const detail = useCredentialGroupDetail(workspaceId, groupId) - const slackBots = useWorkspaceCredentials({ - workspaceId, - type: 'service_account', - providerId: SLACK_CUSTOM_BOT_PROVIDER_ID, - }) - const resend = useResendCredentialGroupEnrollment() - const deleteEnrollment = useDeleteCredentialGroupEnrollment() - const updateGroup = useUpdateCredentialGroup() - const [activeTab, setActiveTab] = useQueryState(credentialGroupTabParam.key, { - ...credentialGroupTabParam.parser, - ...credentialGroupTabUrlKeys, - }) - const accessEditor = useCredentialGroupAccessEditor({ - workspaceId, - groupId, - enabled: activeTab === 'access', - }) - const [providerSearch, setProviderSearchParam] = useQueryState( - credentialGroupProviderSearchParam.key, - { ...credentialGroupProviderSearchParam.parser, ...credentialGroupProviderSearchUrlKeys } - ) - const setProviderSearch = useDebouncedSearchSetter(setProviderSearchParam) - const [peopleSearch, setPeopleSearchParam] = useQueryState(credentialGroupPeopleSearchParam.key, { - ...credentialGroupPeopleSearchParam.parser, - ...credentialGroupPeopleSearchUrlKeys, - }) - const setPeopleSearch = useDebouncedSearchSetter(setPeopleSearchParam) - const [showInvite, setShowInvite] = useState(false) - const [deletingEnrollmentId, setDeletingEnrollmentId] = useState(null) - const credentialGroup = detail.data?.pages[0]?.credentialGroup - const enrollments = detail.data?.pages.flatMap((page) => page.enrollments) ?? [] - const peopleFilter = peopleSearch.trim().toLowerCase() - /** - * Only the pages already loaded: the enrollment list is cursor-paginated with no - * server-side term, so a match on a later page appears only once it is fetched. - */ - const visibleEnrollments = peopleFilter - ? enrollments.filter((enrollment) => enrollment.email.toLowerCase().includes(peopleFilter)) - : enrollments - /** - * `+` means more people exist than are loaded, so it stays on the total. While - * filtering, the match count is reported against that total rather than replacing - * it — otherwise `People (2+)` reads as a two-person group with more to come. - */ - const loadedTotal = `${enrollments.length}${detail.hasNextPage ? '+' : ''}` - const peopleLabel = peopleFilter - ? `People (${visibleEnrollments.length} of ${loadedTotal})` - : `People (${loadedTotal})` - const deletingEnrollment = deletingEnrollmentId - ? (enrollments.find((enrollment) => enrollment.id === deletingEnrollmentId) ?? null) - : null - const configurationReady = - Boolean( - credentialGroup && - (credentialGroup.options.length || - credentialGroup.mcpServers.some( - (server) => server.enabled && server.authType === 'oauth' - )) - ) && - credentialGroup?.options.every( - (option) => - option.provider !== 'slack' || - (option.configurationStatus === 'ready' && - slackBots.data?.some((bot) => bot.id === option.slackBotCredentialId)) - ) - - const guard = useSettingsUnsavedGuard({ - isDirty: accessEditor.dirty, - navigationBlocked: updateGroup.isPending || accessEditor.saving, - }) - const credentialGroupMutationPending = - updateGroup.isPending || accessEditor.saving || resend.isPending || deleteEnrollment.isPending - - const handleTabChange = (value: string) => { - const nextTab = value as CredentialGroupTab - if (nextTab === activeTab) return - guard.guardBack(() => { - accessEditor.discard() - void setActiveTab(nextTab) - }) - } - - const handleEnable = async () => { - if (!credentialGroup) return - try { - await updateGroup.mutateAsync({ - workspaceId, - groupId: credentialGroup.id, - body: { status: 'active' }, - }) - toast.success('Connected accounts enabled') - } catch (error) { - toast.error(getErrorMessage(error, 'Could not enable connected accounts')) - } - } - - const actions: SettingsAction[] = credentialGroup - ? [ - ...(credentialGroup.status === 'disabled' - ? [ - { - text: updateGroup.isPending ? 'Enabling...' : 'Enable accounts', - variant: 'primary' as const, - onSelect: () => void handleEnable(), - disabled: credentialGroupMutationPending, - }, - ] - : []), - ...(activeTab === 'people' - ? [ - { - text: 'Request connections', - icon: Plus, - variant: 'primary' as const, - onSelect: () => setShowInvite(true), - disabled: credentialGroup.status !== 'active' || !configurationReady, - }, - ] - : activeTab === 'access' - ? saveDiscardActions({ - dirty: accessEditor.dirty, - saving: accessEditor.saving, - onSave: () => void accessEditor.save(), - onDiscard: accessEditor.discard, - saveDisabled: !accessEditor.isReady, - saveTooltip: !accessEditor.isReady ? 'Workflow access is unavailable' : undefined, - }) - : []), - ] - : [] - - const handleResend = async (enrollment: CredentialGroupEnrollment) => { - try { - await resend.mutateAsync({ workspaceId, groupId, enrollmentId: enrollment.id }) - toast.success(`Invitation resent to ${enrollment.email}`) - } catch (error) { - toast.error(getErrorMessage(error, 'Failed to resend invitation')) - } - } - - const handleDeleteEnrollment = async () => { - if (!deletingEnrollment) return - try { - await deleteEnrollment.mutateAsync({ - workspaceId, - groupId, - enrollmentId: deletingEnrollment.id, - }) - toast.success(`${deletingEnrollment.email} deleted`) - setDeletingEnrollmentId(null) - } catch (error) { - toast.error(getErrorMessage(error, 'Failed to delete person')) - } - } - - return ( - <> - - {detail.error ? ( - - {getErrorMessage(detail.error, "Couldn't load connected accounts")} - - ) : detail.isPending || !credentialGroup ? null : ( - <> - - - {activeTab === 'details' && ( - <> - - - )} - - {activeTab === 'people' && ( - void detail.fetchNextPage()} - disabled={detail.isFetchingNextPage} - > - {detail.isFetchingNextPage ? 'Loading...' : 'Load more'} - - ) : undefined - } - > - {visibleEnrollments.length === 0 ? ( - - {peopleFilter ? 'No people match your search' : 'No people invited yet'} - - ) : ( -
- {visibleEnrollments.map((enrollment) => { - return ( - } - iconVariant='custom' - title={enrollment.email} - description={ - - } - trailing={ - void handleResend(enrollment), - disabled: resend.isPending, - }, - { - label: 'Delete', - destructive: true, - onSelect: () => setDeletingEnrollmentId(enrollment.id), - }, - ]} - /> - } - /> - ) - })} -
- )} -
- )} - - {activeTab === 'access' && ( - - )} - - )} -
- {credentialGroup && ( - - )} - - !open && !deleteEnrollment.isPending && setDeletingEnrollmentId(null) - } - srTitle='Delete person' - title='Delete person' - text={[ - `Delete ${deletingEnrollment?.email ?? 'this person'}?`, - { - text: ' Their invitation link will stop working and the accounts they connected here will be removed.', - error: true, - }, - ]} - dismissLabel='Cancel' - confirm={{ - label: deleteEnrollment.isPending ? 'Deleting...' : 'Delete', - onClick: handleDeleteEnrollment, - disabled: deleteEnrollment.isPending, - }} - /> - - - ) -} diff --git a/apps/sim/ee/credential-groups/components/credential-group-details.tsx b/apps/sim/ee/credential-groups/components/credential-group-details.tsx deleted file mode 100644 index 073d0b0d6f5..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-details.tsx +++ /dev/null @@ -1,414 +0,0 @@ -'use client' - -import { useState } from 'react' -import { Chip, ChipConfirmModal, ChipTag, toast } from '@sim/emcn' -import { getErrorMessage } from '@sim/utils/errors' -import type { WorkspaceCredential } from '@/lib/api/contracts' -import type { - CredentialGroup, - CredentialGroupOption, - UpdateCredentialGroupBody, -} from '@/lib/api/contracts/credential-groups' -import { getManagedMcpConnectorIcon } from '@/lib/credential-groups/managed-mcp-connector-icons' -import { - MANAGED_MCP_CONNECTOR_IDS, - MANAGED_MCP_CONNECTORS, - type ManagedMcpConnectorId, -} from '@/lib/credential-groups/managed-mcp-connectors' -import { - CREDENTIAL_GROUP_PROVIDER_IDS, - type CredentialGroupProvider, - type CredentialGroupStandardOAuthProvider, - getCredentialGroupProviderService, - getCredentialGroupProviderSupport, - isCredentialGroupStandardOAuthProvider, -} from '@/lib/credential-groups/providers' -import { SLACK_MANAGED_USER_SCOPES } from '@/lib/credential-groups/slack-managed-user-scopes' -import { SLACK_CUSTOM_BOT_PROVIDER_ID } from '@/lib/oauth/types' -import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' -import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import { - RESOURCE_LIST_STACK, - SettingsResourceRow, -} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' -import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' -import { CredentialGroupProviderTile } from '@/ee/credential-groups/components/credential-group-provider-tile' -import { SlackManagedUsersModal } from '@/ee/credential-groups/components/slack-managed-users-modal' -import { - useCreateCredentialGroupMcpConnector, - useDeleteCredentialGroupMcpConnector, - useUpdateCredentialGroup, - useWorkspaceAccounts, -} from '@/hooks/queries/credential-groups' -import { useWorkspaceCredentials } from '@/hooks/queries/credentials' - -/** Stable identity so a pending/errored credentials query cannot churn the modal's `bots` prop. */ -const EMPTY_SLACK_BOTS: WorkspaceCredential[] = [] - -interface CredentialGroupDetailsProps { - credentialGroup: CredentialGroup - workspaceId: string - /** Filters the account types offered below; owned by the panel header's search field. */ - providerSearch: string -} - -function toOptionUpdateInput( - option: CredentialGroupOption -): NonNullable[number] { - const common = { - id: option.id, - label: getCredentialGroupProviderService(option.provider).name, - required: false, - } - if (option.provider !== 'slack') return { ...common, provider: option.provider } - return { - ...common, - provider: 'slack', - slackBotCredentialId: option.slackBotCredentialId, - } -} - -export function CredentialGroupDetails({ - credentialGroup, - workspaceId, - providerSearch, -}: CredentialGroupDetailsProps) { - const updateGroup = useUpdateCredentialGroup() - const createMcpConnector = useCreateCredentialGroupMcpConnector() - const deleteMcpConnector = useDeleteCredentialGroupMcpConnector() - /** - * Reads the same cache entry the workspace settings already populated, so the deployment's configured - * providers arrive without a second request. - */ - const accounts = useWorkspaceAccounts(workspaceId) - const availableProviders = accounts.data?.availableProviders - const slackBots = useWorkspaceCredentials({ - workspaceId, - type: 'service_account', - providerId: SLACK_CUSTOM_BOT_PROVIDER_ID, - }) - const [slackSetup, setSlackSetup] = useState<{ credentialId?: string } | null>(null) - const [removingProvider, setRemovingProvider] = useState(null) - const [removingMcpConnector, setRemovingMcpConnector] = useState( - null - ) - - const isUpdating = - updateGroup.isPending || createMcpConnector.isPending || deleteMcpConnector.isPending - - const updateOptions = async ( - options: NonNullable, - successMessage: string - ) => { - try { - await updateGroup.mutateAsync({ - workspaceId, - groupId: credentialGroup.id, - body: { options }, - }) - toast.success(successMessage) - return true - } catch (error) { - toast.error(getErrorMessage(error, 'Could not update connected accounts')) - return false - } - } - - const addProvider = async (provider: CredentialGroupStandardOAuthProvider) => { - const service = getCredentialGroupProviderService(provider) - const existing = credentialGroup.options.map(toOptionUpdateInput) - const nextOption: NonNullable[number] = { - provider, - label: service.name, - required: false, - } - return updateOptions([...existing, nextOption], `${service.name} added`) - } - - const openSlackSetup = (credentialId?: string) => { - setSlackSetup({ credentialId }) - } - - const handleProviderAction = (provider: CredentialGroupProvider) => { - const support = getCredentialGroupProviderSupport(provider) - if (isCredentialGroupStandardOAuthProvider(provider)) { - void addProvider(provider) - return - } - if (support.configuration === 'slack_custom_bot') { - openSlackSetup() - return - } - throw new Error(`Unsupported Credential Group configuration: ${support.configuration}`) - } - - const handleRemoveProvider = async () => { - if (!removingProvider) return - const service = getCredentialGroupProviderService(removingProvider) - const options = credentialGroup.options - .filter((option) => option.provider !== removingProvider) - .map(toOptionUpdateInput) - if (await updateOptions(options, `${service.name} removed`)) setRemovingProvider(null) - } - - const addMcpConnector = async (connectorId: Exclude) => { - try { - await createMcpConnector.mutateAsync({ - workspaceId, - groupId: credentialGroup.id, - body: { connectorId }, - }) - toast.success(`${MANAGED_MCP_CONNECTORS[connectorId].name} added`) - } catch (error) { - toast.error(getErrorMessage(error, 'Could not add MCP app')) - } - } - - const handleRemoveMcpConnector = async () => { - if (!removingMcpConnector) return - const connector = MANAGED_MCP_CONNECTORS[removingMcpConnector] - try { - await deleteMcpConnector.mutateAsync({ - workspaceId, - groupId: credentialGroup.id, - connectorId: removingMcpConnector, - }) - toast.success(`${connector.name} removed`) - setRemovingMcpConnector(null) - } catch (error) { - toast.error(getErrorMessage(error, 'Could not remove MCP app')) - } - } - - /** - * A provider whose OAuth client this deployment has not configured can never finish an - * enrollment, so it is not offered — but one already on the group stays listed regardless, or - * the row that removes it would disappear along with it. - */ - const configuredProviders = new Set(credentialGroup.options.map((option) => option.provider)) - const offerableProviders = availableProviders ? new Set(availableProviders) : null - const providerQuery = providerSearch.trim().toLowerCase() - const shownProviders = CREDENTIAL_GROUP_PROVIDER_IDS.filter((provider) => { - if ( - !configuredProviders.has(provider) && - offerableProviders && - !offerableProviders.has(provider) - ) { - return false - } - if (!providerQuery) return true - return getCredentialGroupProviderService(provider).name.toLowerCase().includes(providerQuery) - }) - const shownMcpConnectors = MANAGED_MCP_CONNECTOR_IDS.filter((connectorId) => { - if ( - !credentialGroup.mcpServers.some((server) => server.managedConnectorId === connectorId) && - !accounts.data?.availableMcpConnectors.includes(connectorId) - ) - return false - if (!providerQuery) return true - const connector = MANAGED_MCP_CONNECTORS[connectorId] - return ( - connector.name.toLowerCase().includes(providerQuery) || - connector.description.toLowerCase().includes(providerQuery) - ) - }) - - return ( - <> - - {shownProviders.length === 0 ? ( - - {providerSearch.trim() - ? `No account types found matching "${providerSearch}"` - : 'No account types are available. Configure an OAuth client to offer one.'} - - ) : null} -
- {shownProviders.map((provider) => { - const service = getCredentialGroupProviderService(provider) - const support = getCredentialGroupProviderSupport(provider) - const option = credentialGroup.options.find( - (candidate) => candidate.provider === provider - ) - const ProviderIcon = service.icon - const slackBot = - provider === 'slack' && option?.provider === 'slack' - ? slackBots.data?.find((bot) => bot.id === option.slackBotCredentialId) - : undefined - const slackNeedsSetup = - provider === 'slack' && - option?.provider === 'slack' && - (!slackBot || option.configurationStatus !== 'ready') - const descriptionText = - provider === 'slack' && option - ? slackBot - ? `${slackBot.displayName}${slackNeedsSetup ? ' · Finish member sign-in setup' : ''}` - : slackBots.isPending - ? 'Loading custom Slack app...' - : 'Custom Slack app unavailable' - : support.description - - return ( - } - title={service.name} - description={descriptionText} - badge={ - option && !slackNeedsSetup ? Added : undefined - } - trailing={ - option ? ( -
- {slackNeedsSetup && option.provider === 'slack' && slackBot ? ( - openSlackSetup(slackBot.id)} disabled={isUpdating}> - Continue setup - - ) : null} - - openSlackSetup( - option?.provider === 'slack' - ? option.slackBotCredentialId - : undefined - ), - disabled: isUpdating, - }, - ] - : []), - { - label: 'Remove', - destructive: true, - onSelect: () => setRemovingProvider(provider), - disabled: isUpdating, - }, - ]} - /> -
- ) : ( - handleProviderAction(provider)} - disabled={isUpdating || (provider === 'slack' && slackBots.isPending)} - > - {support.configuration === 'oauth' ? 'Add' : 'Set up'} - - ) - } - /> - ) - })} -
-
- - - {shownMcpConnectors.length === 0 ? ( - - {providerSearch.trim() - ? `No MCP apps found matching "${providerSearch}"` - : 'No MCP apps are available.'} - - ) : null} -
- {shownMcpConnectors.map((connectorId) => { - const connector = MANAGED_MCP_CONNECTORS[connectorId] - const server = credentialGroup.mcpServers.find( - (candidate) => candidate.managedConnectorId === connectorId - ) - const ConnectorIcon = getManagedMcpConnectorIcon(connectorId) - return ( - } - title={server?.name ?? connector.name} - description={ - connectorId === 'databricks' - ? 'Configure Databricks in organization Connected accounts' - : connector.description - } - badge={server ? Added : undefined} - trailing={ - server ? ( - setRemovingMcpConnector(connectorId), - disabled: isUpdating, - }, - ]} - /> - ) : connectorId !== 'databricks' ? ( - void addMcpConnector(connectorId)}> - Add - - ) : undefined - } - /> - ) - })} -
-
- - { - if (!nextOpen) setSlackSetup(null) - }} - bots={slackBots.data ?? EMPTY_SLACK_BOTS} - isLoading={slackBots.isPending} - error={slackBots.error} - initialCredentialId={slackSetup?.credentialId} - initialRequiredScopes={ - credentialGroup.options.find((option) => option.provider === 'slack')?.requiredScopes ?? - (credentialGroup.options.some((option) => option.provider === 'slack') - ? SLACK_MANAGED_USER_SCOPES - : undefined) - } - /> - - !open && !isUpdating && setRemovingProvider(null)} - srTitle='Remove account type' - title={`Remove ${ - removingProvider ? getCredentialGroupProviderService(removingProvider).name : 'account' - }`} - text='People will no longer be able to connect this account. Previously connected accounts will no longer be available to Search or workflows.' - dismissLabel='Cancel' - confirm={{ - label: isUpdating ? 'Removing...' : 'Remove', - onClick: handleRemoveProvider, - disabled: isUpdating, - }} - /> - - !open && !isUpdating && setRemovingMcpConnector(null)} - srTitle='Remove MCP app' - title={`Remove ${ - removingMcpConnector ? MANAGED_MCP_CONNECTORS[removingMcpConnector].name : 'MCP app' - }`} - text='People will no longer be able to connect this app. Existing OAuth grants and saved tool metadata will be revoked.' - dismissLabel='Cancel' - confirm={{ - label: isUpdating ? 'Removing...' : 'Remove', - onClick: handleRemoveMcpConnector, - disabled: isUpdating, - }} - /> - - ) -} diff --git a/apps/sim/ee/credential-groups/components/credential-group-enrollment-connections.tsx b/apps/sim/ee/credential-groups/components/credential-group-enrollment-connections.tsx deleted file mode 100644 index 500a9205461..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-enrollment-connections.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { McpIcon } from '@/components/icons' -import type { - CredentialGroupEnrollmentConnection, - CredentialGroupEnrollmentMcpConnection, -} from '@/lib/api/contracts/credential-groups' -import { getCredentialGroupProviderService } from '@/lib/credential-groups/providers' -import { resolveCredentialDisplay } from '@/lib/integrations/credential-display' - -interface EnrollmentConnectionsProps { - connections: CredentialGroupEnrollmentConnection[] - mcpConnections: CredentialGroupEnrollmentMcpConnection[] -} - -interface CredentialProviderIconProps { - provider: CredentialGroupEnrollmentConnection['provider'] -} - -function CredentialProviderIcon({ provider }: CredentialProviderIconProps) { - if (provider === 'gitlab') { - const display = resolveCredentialDisplay({ - type: 'personal_token', - providerId: provider, - displayName: provider, - }) - const Icon = display.icon - return Icon ? : null - } - const ProviderIcon = getCredentialGroupProviderService(provider).icon - return -} - -export function EnrollmentConnections({ connections, mcpConnections }: EnrollmentConnectionsProps) { - const connected = connections.filter((connection) => connection.status === 'active') - const connectedMcp = mcpConnections.filter((connection) => connection.status === 'active') - const count = - connected.reduce((total, connection) => total + connection.count, 0) + connectedMcp.length - const providers = [...new Set(connected.map((connection) => connection.provider))] - - return ( - - {providers.map((provider) => { - return - })} - {connectedMcp.length > 0 ? : null} - - {count} {count === 1 ? 'account' : 'accounts'} connected - - - ) -} diff --git a/apps/sim/ee/credential-groups/components/credential-group-invite-modal.tsx b/apps/sim/ee/credential-groups/components/credential-group-invite-modal.tsx deleted file mode 100644 index 071ca703dbe..00000000000 --- a/apps/sim/ee/credential-groups/components/credential-group-invite-modal.tsx +++ /dev/null @@ -1,122 +0,0 @@ -'use client' - -import { useCallback, useState } from 'react' -import { - ChipModal, - ChipModalBody, - ChipModalError, - ChipModalField, - ChipModalFooter, - ChipModalHeader, - toast, -} from '@sim/emcn' -import { getErrorMessage } from '@sim/utils/errors' -import { quickValidateEmail } from '@/lib/messaging/email/validation' -import { useInviteCredentialGroupEnrollments } from '@/hooks/queries/credential-groups' - -interface CredentialGroupInviteModalProps { - open: boolean - onOpenChange: (open: boolean) => void - workspaceId: string - groupId: string -} - -function validateEmail(email: string): string | null { - const result = quickValidateEmail(email) - return result.isValid ? null : (result.reason ?? 'Invalid email') -} - -export function CredentialGroupInviteModal({ - open, - onOpenChange, - workspaceId, - groupId, -}: CredentialGroupInviteModalProps) { - const invite = useInviteCredentialGroupEnrollments() - const [emails, setEmails] = useState([]) - const [deliveryError, setDeliveryError] = useState(null) - const canSubmit = emails.length > 0 && !invite.isPending - - const handleEmailsChange = useCallback((next: string[]) => { - setEmails(next) - setDeliveryError(null) - }, []) - - const handleOpenChange = (nextOpen: boolean) => { - if (invite.isPending) return - onOpenChange(nextOpen) - if (!nextOpen) { - setEmails([]) - setDeliveryError(null) - invite.reset() - } - } - - const handleSubmit = async () => { - if (!canSubmit) return - setDeliveryError(null) - try { - const result = await invite.mutateAsync({ - workspaceId, - groupId, - body: { emails }, - }) - const failures = result.results.filter((item) => !item.success) - if (failures.length === 0) { - toast.success( - result.sentCount === 1 - ? 'Connection request sent' - : `${result.sentCount} connection requests sent` - ) - handleOpenChange(false) - return - } - - setEmails(failures.map((item) => item.email)) - setDeliveryError( - result.sentCount > 0 - ? `${result.sentCount} sent. ${failures.length} failed: ${failures.map((item) => item.email).join(', ')}` - : `No invitations were sent: ${failures.map((item) => `${item.email} (${item.error})`).join(', ')}` - ) - } catch { - return - } - } - - return ( - - handleOpenChange(false)}> - Request account connections - - - - - {deliveryError ?? - (invite.error ? getErrorMessage(invite.error, 'Failed to send invitations') : null)} - - - handleOpenChange(false)} - cancelDisabled={invite.isPending} - primaryAction={{ - label: invite.isPending ? 'Sending...' : 'Send requests', - onClick: handleSubmit, - disabled: !canSubmit, - }} - /> - - ) -} diff --git a/apps/sim/ee/workspace-forking/application/lineage-details.ts b/apps/sim/ee/workspace-forking/application/lineage-details.ts index d7656da859c..0b640febdc0 100644 --- a/apps/sim/ee/workspace-forking/application/lineage-details.ts +++ b/apps/sim/ee/workspace-forking/application/lineage-details.ts @@ -1,6 +1,7 @@ import { db } from '@sim/db' import { workspace } from '@sim/db/schema' import { eq } from 'drizzle-orm' +import { readForkSyncNewWorkflowsExcluded } from '@/lib/workflows/persistence/new-workflow-row' import { getEffectiveWorkspacePermission } from '@/lib/workspaces/permissions/utils' import { getForkChildren, getForkParent } from '@/ee/workspace-forking/lib/lineage/lineage' import { getUndoableRunForTarget } from '@/ee/workspace-forking/lib/promote/promote-run-store' @@ -34,10 +35,12 @@ export const getWorkspaceForkLineageDetails = defineForkUseCase({ context: { userId: string } }) { const { workspaceId } = input - const [rawParent, rawChildren, run] = await Promise.all([ + const [rawParent, rawChildren, run, forkSyncNewWorkflowsExcluded] = await Promise.all([ getForkParent(workspaceId), getForkChildren(workspaceId), getUndoableRunForTarget(db, workspaceId), + // Lineage-uniform, so this workspace's own value is the lineage's value. + readForkSyncNewWorkflowsExcluded(db, workspaceId), ]) const [parent, children] = await Promise.all([ @@ -71,6 +74,7 @@ export const getWorkspaceForkLineageDetails = defineForkUseCase({ createdAt: child.createdAt.toISOString(), })), undoableRun, + forkSyncNewWorkflowsExcluded, } }, }) diff --git a/apps/sim/ee/workspace-forking/application/operations.ts b/apps/sim/ee/workspace-forking/application/operations.ts index bdc5871fe89..e744d99f92f 100644 --- a/apps/sim/ee/workspace-forking/application/operations.ts +++ b/apps/sim/ee/workspace-forking/application/operations.ts @@ -98,4 +98,16 @@ export const forkOperations = { id: 'workspaces.fork.exclusions', oauthScope: 'api:write', }), + /** + * Admin on the calling workspace is sufficient; the write fans out to the whole lineage + * because the default must be uniform, and it never moves an existing workflow. + * + * permission-group-exempt: the new-workflow fork-sync default is workspace configuration governed by the admin role. + */ + syncDefault: defineWorkspaceOperation({ + ...adminPolicy, + capability: 'none', + id: 'workspaces.fork.sync_default', + oauthScope: 'api:write', + }), } as const diff --git a/apps/sim/ee/workspace-forking/application/recovery-and-mappings.ts b/apps/sim/ee/workspace-forking/application/recovery-and-mappings.ts index 0b8a5898a79..f679f2686e2 100644 --- a/apps/sim/ee/workspace-forking/application/recovery-and-mappings.ts +++ b/apps/sim/ee/workspace-forking/application/recovery-and-mappings.ts @@ -52,6 +52,8 @@ export const updateWorkspaceForkMappings = defineForkUseCase< input.direction === 'push' ? input.otherWorkspaceId : input.workspaceId return db.transaction(async (tx) => { await setForkLockTimeout(tx) + // Rank 4 - see the rank table on `acquireForkLineageLock`. No target lock: this + // rewrites only the edge's mapping rows. await acquireForkEdgeLock(tx, edge.childWorkspaceId) const [currentEdge] = await tx .select({ parentId: workspace.forkedFromWorkspaceId }) diff --git a/apps/sim/ee/workspace-forking/application/revision.ts b/apps/sim/ee/workspace-forking/application/revision.ts index cb3fb69beeb..1bfb81aaf92 100644 --- a/apps/sim/ee/workspace-forking/application/revision.ts +++ b/apps/sim/ee/workspace-forking/application/revision.ts @@ -140,7 +140,12 @@ export async function loadForkPreviewRevision( } } -/** Locks normalized graph rows as well as workflow metadata, including realtime-only writes. */ +/** + * Locks normalized graph rows as well as workflow metadata, including realtime-only writes. + * + * Rank 5 - see the rank table on `acquireForkLineageLock`. Takes `FOR UPDATE` on `workspace` + * rows, so a caller needing the rank-2 lineage lock must take it first. + */ export async function lockForkRevision(tx: DbTransaction, scope: ForkRevisionScope): Promise { const workspaceIds = [ ...new Set([ diff --git a/apps/sim/ee/workspace-forking/application/sync-default.test.ts b/apps/sim/ee/workspace-forking/application/sync-default.test.ts new file mode 100644 index 00000000000..accfcd5a4d1 --- /dev/null +++ b/apps/sim/ee/workspace-forking/application/sync-default.test.ts @@ -0,0 +1,63 @@ +/** + * @vitest-environment node + */ +import { createSessionPrincipal } from '@sim/testing/factories/principal.factory' +import { auditMock } from '@sim/testing/mocks/audit.mock' +import { resetDbChainMock } from '@sim/testing/mocks/database.mock' +import { permissionsMock, permissionsMockFns } from '@sim/testing/mocks/permissions.mock' +import { posthogServerMock } from '@sim/testing/mocks/posthog-server.mock' +import { + workspaceAuthorizationMock, + workspaceAuthorizationMockFns, +} from '@sim/testing/mocks/workspace-authorization.mock' +import { workspaceForkingAuthzMock } from '@sim/testing/mocks/workspace-forking-authz.mock' +import { workspaceForkingLineageMock } from '@sim/testing/mocks/workspace-forking-lineage.mock' +import { + workspaceForkingLineageRootMock, + workspaceForkingLineageRootMockFns, +} from '@sim/testing/mocks/workspace-forking-lineage-root.mock' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const { mockResolveForkLineageRootId, mockResolveForkLineageWorkspaceIds } = + workspaceForkingLineageRootMockFns + +vi.mock('@sim/audit', () => auditMock) +vi.mock('@/lib/core/application/workspace-authorization', () => workspaceAuthorizationMock) +vi.mock('@/lib/workspaces/permissions/utils', () => permissionsMock) +vi.mock('@/lib/posthog/server', () => posthogServerMock) +vi.mock('@/ee/workspace-forking/lib/lineage/authz', () => workspaceForkingAuthzMock) +vi.mock('@/ee/workspace-forking/lib/lineage/lineage', () => workspaceForkingLineageMock) +vi.mock('@/ee/workspace-forking/lib/lineage/lineage-root', () => workspaceForkingLineageRootMock) + +import { setForkSyncDefault } from '@/ee/workspace-forking/application/sync-default' + +const principal = createSessionPrincipal({ userId: 'actor-1' }) + +beforeEach(() => { + resetDbChainMock() + permissionsMockFns.mockGetWorkspaceWithOwner.mockResolvedValue({ + id: 'fork-a', + name: 'Fork A', + organizationId: null, + allowPersonalApiKeys: true, + }) + workspaceAuthorizationMockFns.mockAuthorizeWorkspaceOperation.mockResolvedValue(undefined) + mockResolveForkLineageRootId.mockResolvedValue('root-ws') +}) + +/** + * The lineage-wide write and its audit fan-out are proven against real Postgres in + * `fork-sync.integration.ts`. This covers the one branch that suite cannot stage: an unlink + * committing between the root walk and the lineage lock. + */ +describe('setForkSyncDefault', () => { + it('refuses when the locked root no longer reaches the calling workspace', async () => { + mockResolveForkLineageWorkspaceIds.mockResolvedValue(['root-ws', 'fork-b']) + await expect( + setForkSyncDefault.execute({ + principal, + input: { workspaceId: 'fork-a', excludeNewWorkflows: true }, + }) + ).rejects.toMatchObject({ statusCode: 409 }) + }) +}) diff --git a/apps/sim/ee/workspace-forking/application/sync-default.ts b/apps/sim/ee/workspace-forking/application/sync-default.ts new file mode 100644 index 00000000000..8c5592aa3ca --- /dev/null +++ b/apps/sim/ee/workspace-forking/application/sync-default.ts @@ -0,0 +1,132 @@ +import { AuditAction, AuditResourceType } from '@sim/audit' +import { db } from '@sim/db' +import { workspace } from '@sim/db/schema' +import { and, asc, inArray, isNull, ne } from 'drizzle-orm' +import { captureServerEvent } from '@/lib/posthog/server' +import { defineForkUseCase } from '@/ee/workspace-forking/application/authorized-fork-use-case' +import { forkOperations } from '@/ee/workspace-forking/application/operations' +import { ForkError } from '@/ee/workspace-forking/lib/lineage/authz' +import { + acquireForkLineageLock, + setForkLockTimeout, +} from '@/ee/workspace-forking/lib/lineage/lineage' +import { + resolveForkLineageRootId, + resolveForkLineageWorkspaceIds, +} from '@/ee/workspace-forking/lib/lineage/lineage-root' + +export interface SetForkSyncDefaultInput { + workspaceId: string + excludeNewWorkflows: boolean +} + +export interface SetForkSyncDefaultResult { + excludeNewWorkflows: boolean + /** + * Exactly the lineage members whose value changed, empty when it already matched + * everywhere. The audit fan-out projects one entry per element, and the surface derives + * its `workspacesUpdated` count from the length - one source of truth, so the count can + * never disagree with the entries actually filed. + */ + changedWorkspaces: Array<{ id: string; name: string }> +} + +/** + * Set whether newly created workflows start OUTSIDE fork sync, for an entire fork lineage. + * + * Admin on the calling workspace is enough: the default is meaningless unless it is + * uniform across a lineage, so the write fans out to every ancestor and descendant. It is + * forward-only - no existing workflow's `forkSyncExcluded` is touched, so flipping it can + * never move a workflow in or out of sync behind an admin's back. + * + * Serialized on the lineage-root advisory lock, which fork creation also takes, so a fork + * created concurrently cannot inherit a stale value. + */ +export const setForkSyncDefault = defineForkUseCase< + typeof forkOperations.syncDefault, + SetForkSyncDefaultInput, + SetForkSyncDefaultResult +>({ + operation: forkOperations.syncDefault, + async execute({ input }) { + // The root is the lock key, so it is resolved before the lock; membership is expanded under it. + const rootId = await resolveForkLineageRootId(db, input.workspaceId) + return db.transaction(async (tx) => { + await setForkLockTimeout(tx) + // Rank 2 - see the rank table on `acquireForkLineageLock`. + await acquireForkLineageLock(tx, rootId) + // Expanded under the lock, so a fork created a moment ago is included and one being + // created now waits on the same key. A root that no longer reaches the caller means an + // unlink moved it before we locked, and this key no longer covers its lineage. + const lineageWorkspaceIds = await resolveForkLineageWorkspaceIds(tx, rootId) + if (!lineageWorkspaceIds.includes(input.workspaceId)) { + throw new ForkError( + 'The fork lineage changed while this request was being applied. Try again.', + 409 + ) + } + // Rank 6: lock the live members whose value differs, in id order, since a multi-row + // UPDATE locks in plan order and could deadlock against other multi-workspace writers. + // NO KEY UPDATE keeps FK inserts into these workspaces (KEY SHARE) from queueing behind + // the write. Nothing else writes this column under the lineage lock, so the filter holds. + const toChange = await tx + .select({ id: workspace.id }) + .from(workspace) + .where( + and( + inArray(workspace.id, lineageWorkspaceIds), + isNull(workspace.archivedAt), + ne(workspace.forkSyncNewWorkflowsExcluded, input.excludeNewWorkflows) + ) + ) + .orderBy(asc(workspace.id)) + .for('no key update') + if (toChange.length === 0) { + return { excludeNewWorkflows: input.excludeNewWorkflows, changedWorkspaces: [] } + } + const changed = await tx + .update(workspace) + .set({ forkSyncNewWorkflowsExcluded: input.excludeNewWorkflows, updatedAt: new Date() }) + .where( + inArray( + workspace.id, + toChange.map((member) => member.id) + ) + ) + .returning({ id: workspace.id, name: workspace.name }) + return { excludeNewWorkflows: input.excludeNewWorkflows, changedWorkspaces: changed } + }) + }, + /** One entry per member whose value changed, so every affected workspace's admins see it. */ + projectAudit: ({ input, context, result }) => + result.changedWorkspaces.map((member) => ({ + action: AuditAction.WORKSPACE_FORK_SYNC_DEFAULT_CHANGED, + // The audit wrapper defaults `workspaceId` to the caller; file each entry in its own workspace. + workspaceId: member.id, + resourceType: AuditResourceType.WORKSPACE, + resourceId: member.id, + resourceName: member.name, + description: input.excludeNewWorkflows + ? 'New workflows no longer sync to forks by default' + : 'New workflows sync to forks by default', + metadata: { + forkSyncNewWorkflowsExcluded: input.excludeNewWorkflows, + originWorkspaceId: context.workspace.id, + originWorkspaceName: context.workspace.name, + workspacesChanged: result.changedWorkspaces.length, + }, + })), + afterSuccess({ context, input, result }) { + if (result.changedWorkspaces.length === 0) return + captureServerEvent( + context.userId, + 'fork_sync_default_updated', + { + workspace_id: input.workspaceId, + fork_sync_new_workflows_excluded: input.excludeNewWorkflows, + workspaces_updated: result.changedWorkspaces.length, + }, + { groups: { workspace: input.workspaceId } } + ) + }, +}) diff --git a/apps/sim/ee/workspace-forking/components/fork-sync-default-toggle/fork-sync-default-toggle.tsx b/apps/sim/ee/workspace-forking/components/fork-sync-default-toggle/fork-sync-default-toggle.tsx new file mode 100644 index 00000000000..f2f86ca30b9 --- /dev/null +++ b/apps/sim/ee/workspace-forking/components/fork-sync-default-toggle/fork-sync-default-toggle.tsx @@ -0,0 +1,58 @@ +'use client' + +import { ChipSwitch, Label, toast } from '@sim/emcn' +import { getErrorMessage } from '@sim/utils/errors' +import { useUpdateForkSyncDefault } from '@/ee/workspace-forking/hooks/workspace-fork' + +/** Both outcomes named, so "off" does not have to be inferred from the label. */ +const FORK_SYNC_DEFAULT_OPTIONS = [ + { value: 'sync', label: 'Sync' }, + { value: 'exclude', label: "Don't sync" }, +] as const + +interface ForkSyncDefaultToggleProps { + workspaceId: string + /** The lineage's stored policy: true means new workflows start outside fork sync. */ + excludeNewWorkflows: boolean +} + +/** + * Whether a newly created workflow in this lineage joins fork sync automatically. + * + * Positive polarity, matching the checkbox list below it; this component owns the inversion + * from the stored `forkSyncNewWorkflowsExcluded`. The write reaches every workspace in the + * lineage and is forward-only: no existing workflow moves. + */ +export function ForkSyncDefaultToggle({ + workspaceId, + excludeNewWorkflows, +}: ForkSyncDefaultToggleProps) { + const updateDefault = useUpdateForkSyncDefault() + + return ( +
+
+ {/* No `htmlFor`: `ChipSwitch` is a radio group that takes no id; it carries its own `aria-label`. */} + +

+ Applies to every workspace in this fork lineage. +

+
+ + updateDefault.mutate( + { workspaceId, body: { excludeNewWorkflows: value === 'exclude' } }, + { + onError: (error) => + toast.error(getErrorMessage(error, 'Failed to update the fork sync default')), + } + ) + } + /> +
+ ) +} diff --git a/apps/sim/ee/workspace-forking/components/fork-sync/fork-sync-view.tsx b/apps/sim/ee/workspace-forking/components/fork-sync/fork-sync-view.tsx index d4309868a56..df4cf34dc98 100644 --- a/apps/sim/ee/workspace-forking/components/fork-sync/fork-sync-view.tsx +++ b/apps/sim/ee/workspace-forking/components/fork-sync/fork-sync-view.tsx @@ -812,20 +812,20 @@ export function ForkSyncView({ controller, onDirectionChange }: ForkSyncViewProp controller.inlineSecretCount > 0 || controller.triggerUrlChanges.length > 0 - // Excluded workflows render greyed in the change list. Orient each name's tooltip - // to WHERE it is excluded (that's the only place it can be re-included): the sync's - // source is this workspace on push and the other workspace on pull. + // Unsynced workflows render greyed in the change list. Orient each name's tooltip + // to WHERE it is unsynced (that's the only place it can be re-selected, under Synced + // workflows): the sync's source is this workspace on push and the other on pull. const excludedRows = [ ...(controller.direction === 'push' ? controller.excludedSourceWorkflows : controller.excludedTargetWorkflows - ).map((name) => ({ name, tooltip: 'Excluded from sync' })), + ).map((name) => ({ name, tooltip: 'Not synced' })), ...(controller.direction === 'push' ? controller.excludedTargetWorkflows : controller.excludedSourceWorkflows ).map((name) => ({ name, - tooltip: `Excluded from sync in "${controller.otherWorkspaceName}"`, + tooltip: `Not synced in "${controller.otherWorkspaceName}"`, })), ] @@ -862,8 +862,8 @@ export function ForkSyncView({ controller, onDirectionChange }: ForkSyncViewProp {/* Always shown once the diff loads so the user sees the section even with nothing deployed - an empty change list means the source has no deployed workflows (every deployed workflow appears here, changed or not), so the muted state nudges a deploy. - Sync-excluded workflows list greyed at the end, with a tooltip naming where the - exclusion lives - the sync will not touch them. */} + Unsynced workflows list greyed at the end, with a tooltip naming which workspace + they are unsynced in - the sync will not touch them. */} {controller.hasDiff ? ( {controller.workflowChanges.length + excludedRows.length > 0 ? ( diff --git a/apps/sim/ee/workspace-forking/components/fork-excluded-workflows/fork-excluded-workflows.tsx b/apps/sim/ee/workspace-forking/components/fork-synced-workflows/fork-synced-workflows.tsx similarity index 61% rename from apps/sim/ee/workspace-forking/components/fork-excluded-workflows/fork-excluded-workflows.tsx rename to apps/sim/ee/workspace-forking/components/fork-synced-workflows/fork-synced-workflows.tsx index 80d50291557..f7a03674c28 100644 --- a/apps/sim/ee/workspace-forking/components/fork-excluded-workflows/fork-excluded-workflows.tsx +++ b/apps/sim/ee/workspace-forking/components/fork-synced-workflows/fork-synced-workflows.tsx @@ -1,10 +1,11 @@ 'use client' import { useId, useMemo, useState } from 'react' -import { Checkbox, ChevronDown, cn, OverflowText, toast } from '@sim/emcn' +import { Checkbox, cn, OverflowText, toast } from '@sim/emcn' +import { ChevronDown } from '@sim/emcn/icons' import { getErrorMessage } from '@sim/utils/errors' import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import { useUpdateForkExcludedWorkflows } from '@/ee/workspace-forking/hooks/workspace-fork' +import { useUpdateForkSyncedWorkflows } from '@/ee/workspace-forking/hooks/workspace-fork' import { useFolders } from '@/hooks/queries/folders' import { useWorkflows } from '@/hooks/queries/workflows' import type { WorkflowFolder } from '@/stores/folders/types' @@ -16,16 +17,16 @@ const INDENT_PER_LEVEL = 20 /** Guide-line offset within a level: the horizontal center of the `sm` checkbox. */ const GUIDE_OFFSET = 7 -interface ExcludedWorkflowItem { +interface SyncWorkflowItem { id: string name: string } -interface ExcludedTreeFolder { +interface SyncTreeFolder { id: string name: string - children: ExcludedTreeFolder[] - workflows: ExcludedWorkflowItem[] + children: SyncTreeFolder[] + workflows: SyncWorkflowItem[] /** Every deployed workflow id in this folder's subtree, for the folder-level select-all. */ descendantWorkflowIds: string[] } @@ -36,10 +37,10 @@ interface ExcludedTreeFolder { * a workflow whose folder was deleted falls into the root bucket so it stays selectable. * Folders sort like the sidebar (sortOrder, then name); workflows keep the list order. */ -export function buildExcludedWorkflowTree( +function buildForkSyncWorkflowTree( workflows: WorkflowMetadata[], folders: WorkflowFolder[] -): { folders: ExcludedTreeFolder[]; rootWorkflows: ExcludedWorkflowItem[] } { +): { folders: SyncTreeFolder[]; rootWorkflows: SyncWorkflowItem[] } { const folderById = new Map(folders.map((folder) => [folder.id, folder])) const childFolders = new Map() for (const folder of folders) { @@ -49,12 +50,12 @@ export function buildExcludedWorkflowTree( else childFolders.set(parentId, [folder]) } - const workflowsByFolder = new Map() + const workflowsByFolder = new Map() for (const workflow of workflows) { if (!workflow.isDeployed || workflow.archivedAt) continue const folderId = workflow.folderId && folderById.has(workflow.folderId) ? workflow.folderId : null - const item: ExcludedWorkflowItem = { id: workflow.id, name: workflow.name } + const item: SyncWorkflowItem = { id: workflow.id, name: workflow.name } const bucket = workflowsByFolder.get(folderId) if (bucket) bucket.push(item) else workflowsByFolder.set(folderId, [item]) @@ -63,10 +64,10 @@ export function buildExcludedWorkflowTree( const sortFolders = (list: WorkflowFolder[]) => [...list].sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name)) - const buildFolder = (folder: WorkflowFolder): ExcludedTreeFolder | null => { + const buildFolder = (folder: WorkflowFolder): SyncTreeFolder | null => { const children = sortFolders(childFolders.get(folder.id) ?? []) .map(buildFolder) - .filter((child): child is ExcludedTreeFolder => child !== null) + .filter((child): child is SyncTreeFolder => child !== null) const own = workflowsByFolder.get(folder.id) ?? [] if (children.length === 0 && own.length === 0) return null return { @@ -84,54 +85,74 @@ export function buildExcludedWorkflowTree( return { folders: sortFolders(childFolders.get(null) ?? []) .map(buildFolder) - .filter((folder): folder is ExcludedTreeFolder => folder !== null), + .filter((folder): folder is SyncTreeFolder => folder !== null), rootWorkflows: workflowsByFolder.get(null) ?? [], } } -interface ForkExcludedWorkflowsProps { +interface ForkSyncedWorkflowsProps { workspaceId: string } /** - * The Forks page's "Excluded workflows" section body: the workspace's deployed - * workflows in their sidebar folder structure, each with a checkbox. Checked = - * excluded - the workflow never syncs to or from a fork and is not copied into - * new forks. A folder's checkbox toggles its whole subtree at once (tri-state - * while partially excluded). Toggles apply immediately. + * The Forks page's "Synced workflows" section body: the workspace's deployed workflows + * in their sidebar folder structure, each with a checkbox. Checked = SYNCED - the + * workflow participates in promote in both directions and is copied into new forks. + * Unchecked leaves it in this workspace only; it stays deployed and serving, and a + * previously-synced counterpart in another workspace keeps running on its last deployed + * version rather than being archived. A folder's checkbox toggles its whole subtree at + * once (tri-state while partially synced). Toggles apply immediately. + * + * The wire field stays `forkSyncExcluded` (matching the column), so this component owns + * the single inversion between the stored flag and what the user reads. */ -export function ForkExcludedWorkflows({ workspaceId }: ForkExcludedWorkflowsProps) { +export function ForkSyncedWorkflows({ workspaceId }: ForkSyncedWorkflowsProps) { const workflowsQuery = useWorkflows(workspaceId) const foldersQuery = useFolders(workspaceId) - const updateExcluded = useUpdateForkExcludedWorkflows() + const updateSynced = useUpdateForkSyncedWorkflows() const workflows = workflowsQuery.data const folders = foldersQuery.data - const excludedIds = useMemo( + const syncedIds = useMemo( () => - new Set((workflows ?? []).filter((workflow) => workflow.forkSyncExcluded).map((w) => w.id)), + new Set((workflows ?? []).filter((workflow) => !workflow.forkSyncExcluded).map((w) => w.id)), [workflows] ) const tree = useMemo( - () => buildExcludedWorkflowTree(workflows ?? [], folders ?? []), + () => buildForkSyncWorkflowTree(workflows ?? [], folders ?? []), [workflows, folders] ) - const toggle = (workflowIds: string[], excluded: boolean) => { + const toggle = (workflowIds: string[], synced: boolean) => { // Send only real transitions so a folder select-all never writes no-op rows. - const changed = workflowIds.filter((id) => excludedIds.has(id) !== excluded) + const changed = workflowIds.filter((id) => syncedIds.has(id) !== synced) if (changed.length === 0) return - updateExcluded.mutate( - { workspaceId, body: { workflowIds: changed, forkSyncExcluded: excluded } }, + updateSynced.mutate( + { workspaceId, body: { workflowIds: changed, forkSyncExcluded: !synced } }, { onError: (error) => - toast.error(getErrorMessage(error, 'Failed to update excluded workflows')), + toast.error(getErrorMessage(error, 'Failed to update synced workflows')), } ) } - if (workflowsQuery.isLoading || foldersQuery.isLoading) return null + // Both queries keep the previous workspace's rows as placeholder data on a switch; + // rendering them would post workspace A's workflow ids against workspace B. + const isLoading = + workflowsQuery.isPending || + workflowsQuery.isPlaceholderData || + foldersQuery.isPending || + foldersQuery.isPlaceholderData + if (isLoading) return null + + if (workflowsQuery.isError || foldersQuery.isError) { + return ( + + {getErrorMessage(workflowsQuery.error ?? foldersQuery.error, 'Failed to load workflows')} + + ) + } if (tree.folders.length === 0 && tree.rootWorkflows.length === 0) { return ( @@ -144,74 +165,68 @@ export function ForkExcludedWorkflows({ workspaceId }: ForkExcludedWorkflowsProp return (
{tree.folders.map((folder) => ( - ))} {tree.rootWorkflows.map((workflow) => ( - ))}
) } -interface ExcludedFolderRowProps { - folder: ExcludedTreeFolder +interface SyncFolderRowProps { + folder: SyncTreeFolder level: number - excludedIds: ReadonlySet - onToggle: (workflowIds: string[], excluded: boolean) => void + syncedIds: ReadonlySet + onToggle: (workflowIds: string[], synced: boolean) => void disabled: boolean } -function ExcludedFolderRow({ - folder, - level, - excludedIds, - onToggle, - disabled, -}: ExcludedFolderRowProps) { +function SyncFolderRow({ folder, level, syncedIds, onToggle, disabled }: SyncFolderRowProps) { const [expanded, setExpanded] = useState(true) const total = folder.descendantWorkflowIds.length - const selectedCount = folder.descendantWorkflowIds.filter((id) => excludedIds.has(id)).length + const selectedCount = folder.descendantWorkflowIds.filter((id) => syncedIds.has(id)).length const headerState = selectedCount === 0 ? false : selectedCount === total ? true : 'indeterminate' + const countLabel = selectedCount > 0 ? `${selectedCount}/${total}` : String(total) return (
onToggle(folder.descendantWorkflowIds, headerState !== true)} disabled={disabled} />