+
-The system handles the entire processing pipeline for you:
-
-1. **Text Extraction**: Content is extracted from your documents using specialized parsers for each file type
-2. **Intelligent Chunking**: Documents are broken into meaningful chunks with configurable size and overlap
-3. **Embedding Generation**: Vector embeddings are created for semantic search capabilities
-4. **Processing Status**: Track the progress as your documents are processed
-
-## Supported File Types
-
-Sim supports PDF, Word (DOC/DOCX), plain text (TXT), Markdown (MD), HTML, HTM, Excel (XLS/XLSX), PowerPoint (PPT/PPTX), CSV, JSON, and YAML/YML files. Files can be up to 100MB each, with optimal performance for files under 50MB. You can upload multiple documents simultaneously, and PDF files include OCR processing for scanned documents.
-
-## Viewing and Editing Chunks
-
-Once your documents are processed, you can view and edit the individual chunks. This gives you full control over how your content is organized and searched.
-
-
-
-### Chunk Configuration
-
-When creating a knowledge base, you can configure how documents are split into chunks:
-
-| Setting | Unit | Default | Range | Description |
-|---------|------|---------|-------|-------------|
-| **Max Chunk Size** | tokens | 1,024 | 100-4,000 | Maximum size of each chunk (1 token ≈ 4 characters) |
-| **Min Chunk Size** | characters | 100 | 100-2,000 | Minimum chunk size to avoid tiny fragments |
-| **Overlap** | tokens | 200 | 0-500 | Context overlap between consecutive chunks |
-
-You can also pick a chunking strategy (Auto, Text, Recursive, Sentence, Token, or Regex) to control where splits happen. See [Chunking Strategies](/docs/knowledgebase/chunking-strategies) for a breakdown of when to use each.
-
-- **Hierarchical splitting**: Respects document structure (sections, paragraphs, sentences)
-
-### Editing Capabilities
-- **Edit chunk content**: Modify the text content of individual chunks
-- **Adjust chunk boundaries**: Merge or split chunks as needed
-- **Add metadata**: Enhance chunks with additional context
-- **Bulk operations**: Manage multiple chunks efficiently
-
-## Advanced PDF Processing
-
-For PDF documents, Sim offers enhanced processing capabilities:
-
-### OCR Support
-When configured with Azure or [Mistral OCR](https://docs.mistral.ai/ocr/):
-- **Scanned document processing**: Extract text from image-based PDFs
-- **Mixed content handling**: Process PDFs with both text and images
-- **High accuracy**: Advanced AI models ensure accurate text extraction
-
-## Using The Knowledge Block in Workflows
-
-Once your documents are processed, you can use them in your AI workflows through the Knowledge block. This enables Retrieval-Augmented Generation (RAG), allowing your AI agents to access and reason over your document content to provide more accurate, contextual responses.
-
-
-
-### Knowledge Block Features
-- **Semantic search**: Find relevant content using natural language queries
-- **Context integration**: Automatically include relevant chunks in agent prompts
-- **Dynamic retrieval**: Search happens in real-time during workflow execution
-- **Relevance scoring**: Results ranked by semantic similarity
+## How a document becomes searchable
-### Integration Options
-- **System prompts**: Provide context to your AI agents
-- **Dynamic context**: Search and include relevant information during conversations
-- **Multi-document search**: Query across your entire knowledgebase
-- **Filtered search**: Combine with tags for precise content retrieval
+When you upload a document, Sim processes it in the background:
-## Vector Search Technology
+1. **Extract** the text, with a parser for each file type and OCR for scanned PDFs.
+2. **Chunk** it into passages, with a size and overlap you can tune.
+3. **Embed** each chunk as a vector so it can be matched by meaning, not just keywords.
-Sim uses vector search powered by [pgvector](https://github.com/pgvector/pgvector) to understand the meaning and context of your content:
+A document is searchable once its status reads `completed`. Open any document to view, edit, merge, or split its chunks.
-### Semantic Understanding
-- **Contextual search**: Finds relevant content even when exact keywords don't match
-- **Concept-based retrieval**: Understands relationships between ideas
-- **Multi-language support**: Works across different languages
-- **Synonym recognition**: Finds related terms and concepts
+## What you can upload
-### Search Capabilities
-- **Natural language queries**: Ask questions in plain English
-- **Similarity search**: Find conceptually similar content
-- **Hybrid search**: Combines vector and traditional keyword search
-- **Configurable results**: Control the number and relevance threshold of results
+Sim accepts PDF, Word, text, Markdown, HTML, Excel, PowerPoint, CSV, JSON, and YAML files, up to 100 MB each (best under 50 MB). Scanned PDFs work too: with Azure or [Mistral OCR](https://docs.mistral.ai/ocr/) configured, Sim extracts text from image-based pages.
-## Document Management
+## Shaping what a search returns
-### Organization Features
-- **Bulk upload**: Upload multiple files at once via the asynchronous API
-- **Processing status**: Real-time updates on document processing
-- **Search and filter**: Find documents quickly in large collections
-- **Metadata tracking**: Automatic capture of file information and processing details
+Two things control retrieval quality, and each has its own page:
-### Security and Privacy
-- **Secure storage**: Documents stored with enterprise-grade security
-- **Access control**: Workspace-based permissions
-- **Processing isolation**: Each workspace has isolated document processing
-- **Data retention**: Configure document retention policies
+- **Chunking** decides how a document is split. Smaller chunks are more precise; larger ones keep more context. See [chunking strategies](/knowledgebase/chunking-strategies).
+- **Tags** label documents so a search can filter to a subset. See [tags and filtering](/knowledgebase/tags).
-## Getting Started
+To keep a base in sync with an outside source like Google Drive, use a [connector](/knowledgebase/connectors).
-1. **Navigate to your knowledgebase**: Access from your workspace sidebar
-2. **Upload documents**: Drag and drop or select files to upload
-3. **Monitor processing**: Watch as documents are processed and chunked
-4. **Explore chunks**: View and edit the processed content
-5. **Add to workflows**: Use the Knowledge block to integrate with your AI agents
+## Next
-The knowledgebase transforms your static documents into an intelligent, searchable resource that your AI workflows can leverage for more informed and contextual responses.
+
+
+
+
+
+
+
\ No newline at end of file
+ { question: "What file types are supported?", answer: "PDF, Word (DOC/DOCX), plain text (TXT), Markdown (MD), HTML, Excel (XLS/XLSX), PowerPoint (PPT/PPTX), CSV, JSON, and YAML files." },
+ { question: "Is there a file size limit?", answer: "Files can be up to 100 MB each, with best performance under 50 MB." },
+ { question: "Can I edit chunks after processing?", answer: "Yes. You can view, edit, merge, split, and add metadata to individual chunks once a document is processed." },
+ { question: "How does semantic search work?", answer: "Documents are embedded as vectors. When you search, your query is embedded too and compared against the document vectors to find conceptually similar content, even when the exact keywords don't match." },
+ { question: "Does it support scanned PDFs?", answer: "Yes. With Azure or Mistral OCR configured, Sim extracts text from image-based and scanned PDF pages." },
+ { question: "Can I search across multiple knowledge bases?", answer: "Each Knowledge block searches one knowledge base. Use multiple Knowledge blocks in a workflow to search across several." },
+ { question: "How do I control chunk size?", answer: "When you create a knowledge base, you can set the max chunk size (100 to 4,000 tokens), min chunk size (100 to 2,000 characters), and overlap (0 to 500 tokens). See chunking strategies for details." },
+]} />
diff --git a/apps/docs/content/docs/en/knowledgebase/meta.json b/apps/docs/content/docs/en/knowledgebase/meta.json
index 6c42e7be3eb..d04a13a433b 100644
--- a/apps/docs/content/docs/en/knowledgebase/meta.json
+++ b/apps/docs/content/docs/en/knowledgebase/meta.json
@@ -1,4 +1,11 @@
{
"title": "Knowledge Base",
- "pages": ["index", "chunking-strategies", "connectors", "tags"]
+ "pages": [
+ "index",
+ "using-in-workflows",
+ "connectors",
+ "tags",
+ "debugging-retrieval",
+ "chunking-strategies"
+ ]
}
diff --git a/apps/docs/content/docs/en/knowledgebase/tags.mdx b/apps/docs/content/docs/en/knowledgebase/tags.mdx
index 420efbceda0..4cccaa5387f 100644
--- a/apps/docs/content/docs/en/knowledgebase/tags.mdx
+++ b/apps/docs/content/docs/en/knowledgebase/tags.mdx
@@ -1,5 +1,5 @@
---
-title: Tags and Filtering
+title: Tags and filtering
---
import { Callout } from 'fumadocs-ui/components/callout'
diff --git a/apps/docs/content/docs/en/knowledgebase/using-in-workflows.mdx b/apps/docs/content/docs/en/knowledgebase/using-in-workflows.mdx
new file mode 100644
index 00000000000..49baa03d05d
--- /dev/null
+++ b/apps/docs/content/docs/en/knowledgebase/using-in-workflows.mdx
@@ -0,0 +1,85 @@
+---
+title: Using a knowledge base in a workflow
+description: How the Knowledge block searches a knowledge base and what it returns, so an agent can ground its answers in your documents.
+pageType: concept
+---
+
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { WorkflowPreview, SUPPORT_KB_WORKFLOW } from '@/components/workflow-preview'
+
+A **Knowledge block** searches a [knowledge base](/knowledgebase) and hands the matching passages to a later block, so an [Agent](/blocks/agent) can answer from your documents instead of the model's memory alone. It works like asking a librarian for the most relevant excerpts on a topic: you give it a question and get back a ranked, source-labeled list. This page covers searching, narrowing with tags, reranking, and reading the results.
+
+
+
+In this workflow, the Knowledge block searches a base of product docs for the customer's question, and the Agent answers from the passages it returns.
+
+## Search
+
+A **Knowledge block** set to **Search** takes a query, compares it against the chunks in a base, and returns the closest matches. (The block can also manage documents and chunks, but Search is what a workflow uses to retrieve context.) You point it at a knowledge base and give it a query; in our example the query is `
`, the customer's question.
+
+Search is semantic, not keyword matching. The block turns the query into a vector and finds the chunks whose meaning is closest, so "refund timelines" can match a passage that says "we process returns within 14 days" with no shared words.
+
+**Number of Results** (topK) sets how many chunks come back, 10 by default. Fewer give the agent a tight, focused set; more widen the net at the cost of noise and tokens.
+
+You can also search by tags, instead of or alongside a query:
+
+| What you provide | What it does |
+| --- | --- |
+| Query only | Semantic search across every document in the base. The default. |
+| Tags only | Returns documents that match the tags, with no ranking by meaning. |
+| Query and tags | Tags narrow the document set first, then semantic search runs within it. The most precise. |
+
+## Tag Filters
+
+**Tag Filters** restrict a search to documents carrying specific [tags](/knowledgebase/tags). Each filter has three parts: a **Tag** (a tag defined on the base, like `Department`), an **Operator** (`equals`, `contains`, `greater than`, and others depending on the tag's type), and a **Value** to match.
+
+In our example, adding `Department equals "Billing"` makes the search consider only billing documents. Add more filters with the **+** button; multiple filters combine with AND, so a document must match all of them. A filter value can be a fixed string or a reference like ``, so the scope can change per run.
+
+Filters run before the vector comparison, so they make a search both more precise and cheaper. See [Tags and filtering](/knowledgebase/tags) for the full operator list by tag type.
+
+## Rerank Results
+
+**Rerank Results** is an optional second pass. Vector search ranks by raw similarity; reranking re-scores the top matches with a dedicated relevance model (Cohere's rerank models) and reorders them, which sharpens the ordering when the best answer isn't the literal closest vector.
+
+Leave it off for most searches. Turn it on when retrieval returns roughly the right documents but in the wrong order. When enabled, you pick a **Rerank Model**; self-hosted deployments also supply a Cohere API key.
+
+## Retrieved chunks
+
+The Search operation produces an **output** stored under the block's name, the same as any other block. Its main value is `results`: an array of the matched chunks, ranked best first. A later block reads it by reference, for example ``.
+
+{/* VISUAL: output bundle for the Knowledge block. results: array of chunk objects; query: string; totalResults: number. Highlight one result object expanded with its fields. */}
+
+Each result in the array is an object with these fields:
+
+| Field | What it is |
+| --- | --- |
+| `content` | The chunk's text. This is what the agent reads. |
+| `documentName` | The source document's filename, for citation. |
+| `sourceUrl` | A link to the original, if the document came from a [connector](/knowledgebase/connectors). `null` for uploaded files. |
+| `chunkIndex` | The chunk's position within its document. |
+| `similarity` | How close the chunk is to the query, higher is better. For example `0.92`. |
+| `metadata` | The document's attributes, including its tags. |
+| `documentId` | The source document's identifier. |
+
+The output also carries `query` (the text that was searched) and `totalResults` (the count).
+
+To ground an answer, wire the Knowledge block before an [Agent](/blocks/agent) block and reference the chunks in the Agent's prompt with ``. The agent reads the `content` of each result and can cite `documentName` and `sourceUrl`. See [how blocks reference output](/workflows/data-flow) for how one block reads another's output by name.
+
+## When retrieval looks wrong
+
+When the agent's answer is off, the cause is usually in retrieval, not the agent. Read the Knowledge block's output in the [run logs](/logs-debugging) and check the chunks it actually returned:
+
+- **No results, or wrong documents.** A tag filter may be excluding what you want, or the documents may not be indexed yet. A document is only searchable once its processing status is `completed`; while it is `pending`, `processing`, or `failed`, its chunks won't appear.
+- **Low similarity scores across the board.** The query is too vague, or the information simply isn't in the base. Rewrite the query to match how the documents phrase things.
+- **Right documents, wrong order.** Turn on Rerank Results, or raise Number of Results so the relevant chunk is included.
+
+See [debugging retrieval](/knowledgebase/debugging-retrieval) for the full diagnostic path, and [chunking strategies](/knowledgebase/chunking-strategies) for how chunk boundaries shape what a search can return.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/logs-debugging/alerts.mdx b/apps/docs/content/docs/en/logs-debugging/alerts.mdx
new file mode 100644
index 00000000000..144c28264ba
--- /dev/null
+++ b/apps/docs/content/docs/en/logs-debugging/alerts.mdx
@@ -0,0 +1,108 @@
+---
+title: Alerts
+description: Get notified when a workflow fails, slows down, costs too much, or goes quiet.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+An **alert** tells you when your workflows behave in a way you want to know about: repeated failures, a slow run, an expensive run, or no activity at all. You set up an alert once on a workspace, choose the condition that triggers it, and pick how you want to be told.
+
+## Alert rules
+
+An **alert rule** is the condition that fires the alert. Each alert has one rule, configured with its own thresholds.
+
+| Rule | Fires when | Key settings |
+| --- | --- | --- |
+| **Consecutive failures** | the last N runs all errored | count (1 to 100, default 3) |
+| **Failure rate** | the error rate over a window crosses a threshold | percent (1 to 100), window hours (1 to 168) |
+| **Error count** | the number of errors in a window crosses a threshold | count (1 to 1000), window hours |
+| **Latency threshold** | a run takes longer than a fixed time | duration in ms (1s to 1h, default 30s) |
+| **Latency spike** | a run is much slower than the recent average | percent slower (10 to 1000), window hours |
+| **Cost threshold** | a single run costs more than a set amount | dollars (0.01 to 1000, default $1) |
+| **No activity** | no runs happen within a window | hours (1 to 168, default 24) |
+
+The rate-based rules (failure rate, latency spike) need at least 5 runs in the window before they evaluate. No-activity is checked by a background poll rather than on each run. After an alert fires, that alert stays quiet for **1 hour** so a single problem doesn't flood you.
+
+You can scope a rule to all workflows or specific ones, and filter by level (info or error) and by trigger type.
+
+## Delivery channels
+
+An alert can reach you three ways:
+
+- **Webhook** posts a signed JSON payload to a URL you provide.
+- **Email** sends to a list of recipients, up to 10.
+- **Slack** posts to a channel through a connected Slack account.
+
+## Webhook payload
+
+A webhook alert is an HTTP POST with a JSON body:
+
+```json
+{
+ "id": "evt_...",
+ "type": "workflow.execution.completed",
+ "timestamp": 1719907200000,
+ "data": {
+ "workflowId": "wf_...",
+ "workflowName": "Lead scorer",
+ "executionId": "exec_...",
+ "status": "error",
+ "level": "error",
+ "trigger": "api",
+ "startedAt": "2026-06-01T12:00:00.000Z",
+ "endedAt": "2026-06-01T12:00:01.200Z",
+ "totalDurationMs": 1200,
+ "cost": { "total": 0.0042 }
+ }
+}
+```
+
+You can also include the run's `finalOutput`, its `traceSpans` (webhook only), rate-limit status, and usage data by turning those options on for the alert.
+
+## Verifying a webhook
+
+Each delivery is signed so you can confirm it came from Sim. The signature is in the `sim-signature` header:
+
+```
+sim-signature: t=1719907200000,v1=
+```
+
+To verify, compute an HMAC-SHA256 over `{t}.{raw_body}` using your webhook secret, and compare the result to `v1`:
+
+```javascript
+import { createHmac } from 'node:crypto'
+
+function verify(rawBody, signatureHeader, secret) {
+ const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')))
+ const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
+ return expected === parts.v1
+}
+```
+
+Sim also sends `sim-event`, `sim-timestamp`, and an `Idempotency-Key` header on each delivery, so a receiver can dedupe retries.
+
+## Retries
+
+If your endpoint does not return a 2xx, Sim retries up to 5 times with increasing delays of 5s, 15s, 60s, 3m, then 10m, each with a little jitter. After the fifth failure the delivery is marked failed.
+
+## Setting up an alert
+
+Configure alerts in your workspace notification settings, or through the workspace notifications API:
+
+- `GET /api/workspaces/{id}/notifications` lists alerts.
+- `POST /api/workspaces/{id}/notifications` creates one.
+- `PUT /api/workspaces/{id}/notifications/{notificationId}` updates one.
+- `DELETE /api/workspaces/{id}/notifications/{notificationId}` removes one.
+- `POST /api/workspaces/{id}/notifications/{notificationId}/test` sends a test.
+
+Creating or changing an alert needs Write or Admin access to the workspace. A workspace can have up to 10 alerts of each channel type.
+
+## Next
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/logs-debugging/index.mdx b/apps/docs/content/docs/en/logs-debugging/index.mdx
new file mode 100644
index 00000000000..af9aae18112
--- /dev/null
+++ b/apps/docs/content/docs/en/logs-debugging/index.mdx
@@ -0,0 +1,91 @@
+---
+title: Overview
+description: A log is the recorded trace of one workflow run, and debugging is reading that trace backward from the block that failed.
+pageType: concept
+---
+
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+A **log** is the recorded trace of one workflow run. Every time a workflow runs, Sim writes down what triggered it, which blocks ran in what order, and for each block its exact input, its output, and any error. That trace is the ground truth for debugging: it replays what each block received, what it did, and what it returned, so you can find where something went wrong.
+
+Think of it like a video replay of the run, where you read what actually happened one block at a time.
+
+The **Logs page** lists every run across your workspace, one row per run. The [Logging reference](/logs-debugging/logging) covers the page itself: the columns, filters, and sidebar. This page covers what a log captures and how to trace a failure back to its cause.
+
+{/* VISUAL: the Logs page as a list of run rows (Workflow, Date, Status, Cost, Trigger, Duration), one row expanded into its sidebar trace. */}
+
+## What a log records
+
+### The run
+
+Each row on the Logs page is one **run**. It records the **trigger** that started it (manual, api, schedule, chat, webhook, mcp, mothership, copilot, workflow, or a2a), a **status**, a **duration**, and the total **cost**. It also carries an **execution ID** that uniquely names the run.
+
+The status is the run's outcome at a glance: **success**, **error**, **running**, **pending**, or **cancelled**. When you are hunting a failure, you filter the list to **error** and start there.
+
+{/* VISUAL: one run row broken out into its parts, each labeled: trigger badge, status badge, duration, cost, execution ID. */}
+
+### The blocks
+
+Open a run and the sidebar shows its blocks in the order they ran. Each **block execution** records the [block](/blocks)'s name and type, its own status (**success**, **error**, or **skipped**), its timing, its **input**, its **output**, and an error message if it failed.
+
+This is the level you debug at, because a run fails when one of its blocks fails, and a block usually fails because of the input it received.
+
+{/* VISUAL: the sidebar trace, a vertical list of block executions with status dots, one expanded to show its Input/Output tabs. */}
+
+### Input and output
+
+Each block in the sidebar has two tabs. The **Input** tab shows the resolved values the block actually ran with: the literal values you typed, and the earlier outputs it read by reference (with API keys redacted). The **Output** tab shows what the block produced, formatted as an object, with markdown rendered for agent-generated text.
+
+The input tab is the important one. A block reads earlier outputs by name, written ``, and the input tab shows what those references resolved to at run time. If a reference pointed at a value that was not there, you see it here as missing or wrong, not as the tag you wrote. See [how blocks pass data](/workflows/data-flow) for how those references resolve.
+
+{/* VISUAL: the Input tab of an Agent block showing a resolved reference, e.g. the prompt with filled in with its actual value. */}
+
+### The snapshot
+
+A workflow changes over time. A log does not. Clicking **View Snapshot** opens a frozen copy of the workflow exactly as it was when that run happened: the blocks, the connections, the configuration. This matters when a run failed last week and you have edited the workflow since. The snapshot shows the version that actually ran, not today's version.
+
+## Tracing a failure backward
+
+Debugging follows the same repeatable loop each time. You start at the block that failed and walk back to the block that caused it.
+
+1. **Find the failed block.** Open the errored run. The sidebar marks the block whose status is **error**. Read its error message.
+2. **Read its input.** Open the block's Input tab. This is what it actually ran with, after every reference resolved.
+3. **Verify the input.** Ask whether that input is what the block expected. An empty field, a value of the wrong type, a missing nested key: the mismatch is usually visible here.
+4. **Walk back to the source.** A bad input came from somewhere. Find the earlier block whose output the failed block referenced, and open that block's Output tab. Either it produced the wrong value, or it never ran.
+5. **Fix and rerun.** Correct the reference, the configuration, or the upstream block, then run the workflow again.
+6. **Compare the traces.** Open the new run's log next to the old one. The block that was **error** is now **success**, and its input is the value you expected. That confirms the fix.
+
+{/* VISUAL: the debugging loop as a flowchart: failed block → read input → verify expectation → walk back to source block → fix → rerun → compare logs. */}
+
+{/* VISUAL: side-by-side of a failed run and a successful run, same blocks, highlighting the one input/output that changed between them. */}
+
+### Common failures
+
+Most errors come down to a handful of input mismatches. Knowing the shape speeds up step 3.
+
+- **Missing input.** A field the block needs was left empty, or its reference resolved to nothing.
+- **Wrong reference.** The tag names an output that does not exist, or uses the wrong field name.
+- **Type mismatch.** A string where an object was expected, or the reverse.
+- **Missing nested key.** The referenced object exists, but the specific field inside it does not.
+- **Empty agent message.** An [Agent](/blocks/agent) returned nothing, so the next block had nothing to read.
+- **External error.** A tool or API the block called returned an error of its own, surfaced in the block's error message.
+
+When a value is the wrong shape, reshape it in a [Function](/blocks/function) block, whose result becomes its own output that later blocks can read.
+
+## AI-assisted debugging
+
+Mothership and Copilot can read a run's logs and propose a fix from the trace: the error message, the input the block received, and the output the upstream block produced. The logs stay the ground truth. You confirm a proposed fix the same way you confirm your own: rerun the workflow and compare the new trace against the failed one.
+
+## Retention
+
+Logs are kept so you can debug a run after it happened. Free plans retain logs for **7 days**, after which they are archived to cloud storage and removed from the database. Pro, Team, and Enterprise plans retain logs indefinitely.
+
+## Next
+
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/execution/logging.mdx b/apps/docs/content/docs/en/logs-debugging/logging.mdx
similarity index 95%
rename from apps/docs/content/docs/en/execution/logging.mdx
rename to apps/docs/content/docs/en/logs-debugging/logging.mdx
index dbbf50a3835..1ffa5532e22 100644
--- a/apps/docs/content/docs/en/execution/logging.mdx
+++ b/apps/docs/content/docs/en/logs-debugging/logging.mdx
@@ -143,9 +143,9 @@ The snapshot provides:
## Next Steps
-- Learn about [Cost Calculation](/execution/costs) to understand workflow pricing
-- Explore the [External API](/execution/api) for programmatic log access
-- Set up [Notifications](/execution/api#notifications) for real-time alerts via webhook, email, or Slack
+- Learn about [Cost Calculation](/costs) to understand workflow pricing
+- Explore the [External API](/api-reference/getting-started) for programmatic log access
+- Set up [Notifications](/api-reference/getting-started#notifications) for real-time alerts via webhook, email, or Slack
import { FAQ } from '@/components/ui/faq'
diff --git a/apps/docs/content/docs/en/mcp/index.mdx b/apps/docs/content/docs/en/mcp/index.mdx
index 50b731e0d26..e32de78c5ea 100644
--- a/apps/docs/content/docs/en/mcp/index.mdx
+++ b/apps/docs/content/docs/en/mcp/index.mdx
@@ -1,5 +1,5 @@
---
-title: Using MCP Tools
+title: Using MCP tools
description: Connect external tools and services using the Model Context Protocol
---
diff --git a/apps/docs/content/docs/en/meta.json b/apps/docs/content/docs/en/meta.json
index b0446caab8f..f8fd53530f6 100644
--- a/apps/docs/content/docs/en/meta.json
+++ b/apps/docs/content/docs/en/meta.json
@@ -1,32 +1,71 @@
{
"title": "Sim Documentation",
"pages": [
- "---Getting Started---",
+ "---Get Started---",
"./introduction/index",
"./getting-started/index",
- "./quick-reference/index",
- "---Building Workflows---",
- "triggers",
- "blocks",
- "tools",
- "connections",
- "---Features---",
- "mothership",
- "mcp",
- "copilot",
- "mailer",
+ "---Workflows---",
+ "./workflows/index",
+ "./workflows/how-it-runs",
+ "./workflows/data-flow",
+ "./blocks/index",
+ "./triggers/index",
+ "./workflows/connections",
+ "./workflows/variables",
+ "deployment",
+ "---Tables---",
+ "./tables/index",
+ "./tables/using-in-workflows",
+ "./tables/workflow-columns",
+ "---Files---",
+ "./files/index",
+ "./files/using-in-workflows",
+ "./files/generating",
+ "./files/passing-files",
+ "---Knowledge Bases---",
+ "./knowledgebase/index",
+ "./knowledgebase/using-in-workflows",
+ "./knowledgebase/connectors",
+ "./knowledgebase/tags",
+ "./knowledgebase/debugging-retrieval",
+ "./knowledgebase/chunking-strategies",
+ "---Logs & Debugging---",
+ "./logs-debugging/index",
+ "./logs-debugging/logging",
+ "./logs-debugging/alerts",
+ "---Building agents---",
+ "./building-agents/index",
+ "./building-agents/choosing",
+ "./tools/custom-tools",
+ "./mcp/index",
"skills",
- "knowledgebase",
- "tables",
- "variables",
+ "./tools/knowledge",
+ "./tools/memory",
+ "---Mothership---",
+ "./mothership/index",
+ "./mothership/workflows",
+ "./mothership/research",
+ "./mothership/files",
+ "./mothership/tables",
+ "./mothership/tasks",
+ "./mothership/knowledge",
+ "mailer",
+ "---Workspaces & Access---",
+ "./workspaces/fundamentals",
"integrations",
- "credentials",
+ "./permissions/roles-and-permissions",
+ "./credentials/index",
+ "./workspaces/organization",
"---Platform---",
- "execution",
- "permissions",
+ "./costs",
"self-hosting",
"enterprise",
- "./keyboard-shortcuts/index"
+ "---Reference---",
+ "./quick-reference/index",
+ "./keyboard-shortcuts/index",
+ "tools",
+ "blocks",
+ "triggers"
],
"defaultOpen": false
}
diff --git a/apps/docs/content/docs/en/mothership/files.mdx b/apps/docs/content/docs/en/mothership/files.mdx
index 8c6ecae0862..64eb36960e1 100644
--- a/apps/docs/content/docs/en/mothership/files.mdx
+++ b/apps/docs/content/docs/en/mothership/files.mdx
@@ -1,5 +1,5 @@
---
-title: Files & Documents
+title: Files & documents
description: Upload, create, edit, and generate files — documents, presentations, images, and more.
---
diff --git a/apps/docs/content/docs/en/mothership/index.mdx b/apps/docs/content/docs/en/mothership/index.mdx
index e241a9a3467..3f61f20df5a 100644
--- a/apps/docs/content/docs/en/mothership/index.mdx
+++ b/apps/docs/content/docs/en/mothership/index.mdx
@@ -1,5 +1,5 @@
---
-title: Mothership
+title: Building with Mothership
description: Your AI command center. Build and manage your entire workspace in natural language.
---
diff --git a/apps/docs/content/docs/en/mothership/knowledge.mdx b/apps/docs/content/docs/en/mothership/knowledge.mdx
index 008c050b5c2..41c1edbb5d8 100644
--- a/apps/docs/content/docs/en/mothership/knowledge.mdx
+++ b/apps/docs/content/docs/en/mothership/knowledge.mdx
@@ -1,5 +1,5 @@
---
-title: Knowledge Bases
+title: Knowledge bases
description: Create, populate, and query knowledge bases from Mothership.
---
diff --git a/apps/docs/content/docs/en/mothership/tasks.mdx b/apps/docs/content/docs/en/mothership/tasks.mdx
index d66848b9888..ec68e900a5c 100644
--- a/apps/docs/content/docs/en/mothership/tasks.mdx
+++ b/apps/docs/content/docs/en/mothership/tasks.mdx
@@ -1,5 +1,5 @@
---
-title: Automation & Configuration
+title: Automation & configuration
description: Schedule recurring jobs, take immediate actions, connect integrations, and configure your workspace.
---
diff --git a/apps/docs/content/docs/en/mothership/workflows.mdx b/apps/docs/content/docs/en/mothership/workflows.mdx
index e0d0fe330af..d82f22bfe82 100644
--- a/apps/docs/content/docs/en/mothership/workflows.mdx
+++ b/apps/docs/content/docs/en/mothership/workflows.mdx
@@ -78,7 +78,7 @@ Ask: "Deploy the invoice workflow as an API and generate an API key."
Mothership can also roll back: "Revert the billing workflow to the version from last Tuesday."
-See [API Deployment](/execution/api-deployment) and [Chat Deployment](/execution/chat) for full details on each deployment type.
+See [API Deployment](/deployment/api) and [Chat Deployment](/deployment/chat) for full details on each deployment type.
## Organizing Workflows
diff --git a/apps/docs/content/docs/en/permissions/roles-and-permissions.mdx b/apps/docs/content/docs/en/permissions/roles-and-permissions.mdx
index 28cfe8df87e..53cfcccf685 100644
--- a/apps/docs/content/docs/en/permissions/roles-and-permissions.mdx
+++ b/apps/docs/content/docs/en/permissions/roles-and-permissions.mdx
@@ -1,5 +1,5 @@
---
-title: "Roles and Permissions"
+title: Roles and permissions
---
import { Callout } from 'fumadocs-ui/components/callout'
diff --git a/apps/docs/content/docs/en/skills/index.mdx b/apps/docs/content/docs/en/skills/index.mdx
index 73a01f9ad4f..f27c2d33a92 100644
--- a/apps/docs/content/docs/en/skills/index.mdx
+++ b/apps/docs/content/docs/en/skills/index.mdx
@@ -1,5 +1,5 @@
---
-title: Agent Skills
+title: Agent skills
---
import { Callout } from 'fumadocs-ui/components/callout'
diff --git a/apps/docs/content/docs/en/tables/index.mdx b/apps/docs/content/docs/en/tables/index.mdx
index 3ba1f7b515d..ae70683af65 100644
--- a/apps/docs/content/docs/en/tables/index.mdx
+++ b/apps/docs/content/docs/en/tables/index.mdx
@@ -1,158 +1,55 @@
---
-title: Tables
-description: Store, query, and manage structured data directly within your workspace
+title: Overview
+description: A grid of typed columns and rows in your workspace, for data your workflows read and write.
+pageType: concept
---
-import { Callout } from 'fumadocs-ui/components/callout'
import { Image } from '@/components/ui/image'
+import { Card, Cards } from 'fumadocs-ui/components/card'
import { FAQ } from '@/components/ui/faq'
-Tables let you store and manage structured data directly in your workspace. Use them to maintain reference data, collect workflow outputs, or build lightweight databases — all without leaving Sim.
+A **table** is a grid of typed columns in your workspace, like a spreadsheet with a schema. Use one to hold reference data, collect what your workflows produce, or store the structured records your agents read and write.
-
+
+
+
-Each table has a schema of typed columns, supports filtering and sorting, and is fully accessible through the [Tables API](/docs/en/api-reference/(generated)/tables).
+## Column types
-## Creating a Table
+Every column has a type, which decides how its values are stored and validated.
-1. Open the **Tables** section from your workspace sidebar
-2. Click **New table**
-3. Name your table and start adding columns
+| Type | Holds | Example |
+| --- | --- | --- |
+| **Text** | A free-form string | `"Acme Corp"` |
+| **Number** | A numeric value | `42` |
+| **Boolean** | `true` or `false` | `true` |
+| **Date** | A date | `2026-03-16` |
+| **JSON** | An object or array | `{ "tier": "pro" }` |
-Tables start with a single text column. Add more columns by clicking **New column** in the column header area.
+Types are enforced as you enter values, so a Number column only takes numbers.
-## Column Types
+## Editing a table
-Each column has a type that determines how values are stored and validated.
+Open the **Tables** section in the sidebar and click **New table** to create one. Add columns from the column header, type into a cell to edit it, and paste rows from a spreadsheet to bulk-load. Filter and sort from the toolbar without changing the underlying data. The editor has full keyboard support; see [keyboard shortcuts](/keyboard-shortcuts).
-| Type | Description | Example Values |
-|------|-------------|----------------|
-| **Text** | Free-form string | `"Acme Corp"`, `"hello@example.com"` |
-| **Number** | Numeric value | `42`, `3.14`, `-100` |
-| **Boolean** | True or false | `true`, `false` |
-| **Date** | Date value | `2026-03-16` |
-| **JSON** | Structured object or array | `{"key": "value"}`, `[1, 2, 3]` |
+## Tables in workflows
-
-Column types are enforced on input. For example, typing into a Number column is restricted to digits, dots, and minus signs. Non-numeric values entered via paste are coerced to `0`.
-
+A [Table block](/tables/using-in-workflows) reads and writes rows from inside a workflow: query rows for reference data, write results back, or process a batch. A [workflow column](/tables/workflow-columns) goes a step further and runs a workflow against each row on its own. Everything in a table is also available over the [REST API](/api-reference/getting-started).
-## Working with Rows
+## Next
-### Adding Rows
-
-- Click **New row** below the last row to append a new row
-- Press **Shift + Enter** while a cell is selected to insert a row below
-- Paste tabular data (from a spreadsheet or TSV) to bulk-create rows
-
-### Editing Cells
-
-Click a cell to select it, then press **Enter**, **F2**, or start typing to edit. Press **Escape** to cancel, or **Tab** to save and move to the next cell.
-
-### Selecting Rows
-
-Click a row's checkbox to select it. Selecting additional checkboxes adds to the selection without clearing previous selections.
-
-| Action | Behavior |
-|--------|----------|
-| Click checkbox | Toggle that row's selection |
-| Shift + click checkbox | Select range from last clicked to current |
-| Click header checkbox | Select all / deselect all |
-| Shift + Space | Toggle row selection from keyboard |
-
-### Deleting Rows
-
-Right-click a selected row (or group of selected rows) and choose **Delete row** from the context menu.
-
-## Filtering and Sorting
-
-Use the toolbar above the table to filter and sort your data.
-
-- **Filter**: Set conditions on any column (e.g., "Name contains Acme"). Multiple filters are combined with AND logic.
-- **Sort**: Order rows by any column, ascending or descending.
-
-Filters and sorts are applied in real time and do not modify the underlying data.
-
-## Keyboard Shortcuts
-
-All shortcuts work when the table is focused and no cell is being edited.
-
-
-**Mod** refers to `Cmd` on macOS and `Ctrl` on Windows/Linux.
-
-
-### Navigation
-
-| Shortcut | Action |
-|----------|--------|
-| Arrow keys | Move one cell |
-| `Mod` + Arrow keys | Jump to edge of table |
-| `Tab` / `Shift` + `Tab` | Move to next / previous cell |
-| `Escape` | Clear selection |
-
-### Selection
-
-| Shortcut | Action |
-|----------|--------|
-| `Shift` + Arrow keys | Extend selection by one cell |
-| `Mod` + `Shift` + Arrow keys | Extend selection to edge |
-| `Mod` + `A` | Select all rows |
-| `Shift` + `Space` | Toggle current row selection |
-
-### Editing
-
-| Shortcut | Action |
-|----------|--------|
-| `Enter` or `F2` | Start editing selected cell |
-| `Escape` | Cancel editing |
-| Type any character | Start editing with that character |
-| `Shift` + `Enter` | Insert new row below |
-| `Space` | Expand row details |
-
-### Clipboard
-
-| Shortcut | Action |
-|----------|--------|
-| `Mod` + `C` | Copy selected cells |
-| `Mod` + `X` | Cut selected cells |
-| `Mod` + `V` | Paste |
-| `Delete` / `Backspace` | Clear selected cells (all columns when using checkbox selection) |
-
-### History
-
-| Shortcut | Action |
-|----------|--------|
-| `Mod` + `Z` | Undo |
-| `Mod` + `Shift` + `Z` | Redo |
-| `Mod` + `Y` | Redo (alternative) |
-
-## Using Tables in Workflows
-
-Tables can be read from and written to within your workflows using the **Table** block. Common patterns include:
-
-- **Lookup**: Query a table for reference data (e.g., pricing rules, customer metadata)
-- **Write-back**: Store workflow outputs in a table for later review or reporting
-- **Iteration**: Process each row in a table as part of a batch workflow
-
-## API Access
-
-Tables are fully accessible through the REST API. You can create, read, update, and delete both tables and rows programmatically.
-
-See the [Tables API Reference](/docs/en/api-reference/(generated)/tables) for endpoints, parameters, and examples.
-
-## Best Practices
-
-- **Use typed columns** to enforce data integrity — prefer Number and Boolean over storing everything as Text
-- **Name columns descriptively** so they are self-documenting when referenced in workflows
-- **Use JSON columns sparingly** — they are flexible but harder to filter and sort against
-- **Leverage the API** for bulk imports rather than manually entering large datasets
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/tables/using-in-workflows.mdx b/apps/docs/content/docs/en/tables/using-in-workflows.mdx
new file mode 100644
index 00000000000..f5691e00dab
--- /dev/null
+++ b/apps/docs/content/docs/en/tables/using-in-workflows.mdx
@@ -0,0 +1,130 @@
+---
+title: Using tables in workflows
+description: How a workflow reads, writes, and updates table rows with the Table block.
+pageType: guide
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { WorkflowPreview, OutputBundle, TABLE_ENRICH_WORKFLOW } from '@/components/workflow-preview'
+
+A [table](/tables) is a resource: structured rows your workflows read and write. A [Table block](/tools/table) is the step that does the reading and writing inside a workflow. You pick an operation on the block (query rows, insert a row, update rows), point it at a table, and its result is remembered under the block's name for later blocks to use.
+
+A workflow uses whichever Table operations its task needs. It might read rows to work on, write rows produced elsewhere, update rows in place, or just look something up mid-run. This page covers the operations and shows a few ways to combine them.
+
+Throughout this page the running example is a `leads` table with columns `company`, `email`, `description`, and `status`. The goal is to find unprocessed leads, have an Agent classify each one, and write the category back.
+
+
+
+## The Table block
+
+A **Table block** performs one operation against one table. The **Operation** dropdown picks the action; the **Table** selector picks the target. The fields below those two change based on the operation you choose.
+
+{/* VISUAL: Table block UI showing the Operation dropdown open, plus the conditional fields that appear for Query Rows (Filter Conditions, Sort Order, Limit, Offset). */}
+
+The operations fall into three groups:
+
+- **Read:** Query Rows, Get Row by ID, Get Schema.
+- **Write:** Insert Row, Batch Insert Rows, Upsert Row.
+- **Update and delete:** Update Row by ID, Update Rows by Filter, Delete Row by ID, Delete Rows by Filter.
+
+Every row carries three built-in columns alongside your own: `id` (the row's unique identifier), `createdAt`, and `updatedAt`. Sim manages these for you, so you never include them when inserting. You can still filter and sort on them.
+
+## Reading rows
+
+**Query Rows** retrieves rows from a table, with optional filtering, sorting, and pagination. It's how a workflow gets its input from a table.
+
+For our example, the block queries `leads` where `status` equals `unprocessed`. Its output holds the matching rows plus counts:
+
+```
+{ success: true, rows: [ { id: "row_...", company: "Acme", ... } ], rowCount: 5, totalCount: 42 }
+```
+
+Later blocks read these by name: `` is the array, `` is how many came back, `` is how many matched the filter before the limit. (For more on reading outputs by reference, see [how blocks pass data](/workflows/data-flow).)
+
+
+
+**Filter Conditions** narrow the result. In the default **Builder** input mode you add rules visually: pick a column, an operator, and a value. Switch the **Input Mode** to **Editor** to write the filter as an object instead, using operators like `$eq`, `$gt`, `$contains`, and `$in`:
+
+```
+{ status: "unprocessed", createdAt: { $gte: "2026-06-01" } }
+```
+
+**Sort Order** orders the result, again visually in Builder mode or as an object in Editor mode, for example `{ createdAt: "desc" }`. **Limit** caps how many rows come back (default 100, max 1000) and **Offset** skips rows for pagination.
+
+{/* VISUAL: Filter Conditions and Sort Order builders, showing a status = unprocessed rule and a createdAt descending sort, with the equivalent Editor-mode object beside them. */}
+
+For a one-off point lookup, use **Get Row by ID** with a single `Row ID`. **Get Schema** returns the table's column definitions, useful when a workflow needs to inspect structure before writing. The full operator list lives in the [Table block reference](/tools/table).
+
+## Writing rows
+
+**Insert Row** adds one row. Its **Row Data** is an object whose keys match your column names:
+
+```
+{ company: "Acme", email: "deals@acme.com", description: "...", status: "unprocessed" }
+```
+
+The output is the inserted row, including the `id` and timestamps Sim generated for it.
+
+**Batch Insert Rows** adds many rows in one operation (up to 1000) from a **Rows Data** array. Use it instead of looping Insert Row when you have a set of results to load at once. Its output reports `insertedCount`.
+
+**Upsert Row** inserts a row, or updates the existing one if it matches a unique column. Its output includes an `operation` field set to `insert` or `update`, so a later block can tell which happened.
+
+
+Row data must match the table's columns and types. A `number` column rejects `"twenty"`; a `boolean` column wants `true`, not `"true"`. If an Agent produces the value, give it a [structured output](/blocks/agent) so the shape is predictable before it reaches the table.
+
+
+## Updating rows
+
+To change an existing row you either name it or filter for it.
+
+**Update Row by ID** modifies one row. It takes a `Row ID`, often `` from an earlier query, and **Row Data** with only the fields you want to change. Unlisted fields stay as they were.
+
+**Update Rows by Filter** changes every row that matches a filter, which is the right tool when you don't know the IDs. In our example, after the Agent classifies leads, the workflow sets `status` to `qualified` on all rows where `status` is `unprocessed`. The output reports `updatedCount` and the list of `updatedRowIds`.
+
+{/* VISUAL: before/after of the leads table. Left shows rows with status "unprocessed" and an empty category column; right shows the same rows with category filled in and status "qualified". */}
+
+**Delete Row by ID** and **Delete Rows by Filter** remove rows the same two ways, by ID or by filter, and report a `deletedCount`. Deletes are mostly for cleanup, not part of the everyday read-process-write loop.
+
+## Example: enriching rows
+
+One way to combine the operations is to query rows, process them, and write the results back. Here, the workflow classifies unprocessed leads:
+
+1. **Table (Query Rows)** reads `leads` where `status` is `unprocessed`.
+2. **Agent** reads a row's fields, classifies it, and returns a [structured output](/blocks/agent) like `{ category: "enterprise", score: 0.9 }`.
+3. **Table (Update Rows by Filter)** writes the category back and flips `status` to `qualified`.
+
+After the run, the table holds the enriched rows. The next run queries them again, and the `status` column keeps the workflow from reprocessing what it already handled. So the table serves as both the queue the workflow pulls from and the record of what it has already done.
+
+{/* VISUAL: the full three-block chain annotated with the example data at each hop: filter object in, one row's fields into the Agent, the Agent's { category, score } object out, the updated filter write. */}
+
+## Variations
+
+**Lookup mid-run.** A Table block doesn't have to be the first or last step. Place a Query Rows in the middle to fetch reference data while processing: query a `pricing` table by the order's currency, then let the Agent use the result to compute a total.
+
+**Iterate row by row.** Wrap a Query → process → update cycle in a [Loop block](/blocks/loop) to handle one row at a time. This runs sequentially, slower than a batch update but useful when each row needs its own multi-step logic. Inside the loop the Agent reads the current row and an Update Row by ID writes its result.
+
+**Paginate large reads.** Query Rows returns at most 1000 rows. When `totalCount` exceeds your **Limit**, increase **Offset** on each pass (0, then 100, then 200) to walk through the whole table, typically inside a Loop.
+
+## Inspecting reads and writes
+
+Every Table block's input and output is recorded in [logs](/logs-debugging). For a Query block, the log shows the filter and sort it sent and the rows it received. For an Update or Insert, it shows the row data written and the count affected. When a write does nothing or a query comes back empty, the log is where you check the filter and the data shape before looking anywhere else.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/tables/workflow-columns.mdx b/apps/docs/content/docs/en/tables/workflow-columns.mdx
new file mode 100644
index 00000000000..773f8ac09c2
--- /dev/null
+++ b/apps/docs/content/docs/en/tables/workflow-columns.mdx
@@ -0,0 +1,108 @@
+---
+title: Workflow columns
+description: A column backed by a workflow that runs once per row, reading chosen columns as inputs and writing its results back into result columns.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+A [table](/tables) is a grid of typed columns. Usually you type a column's values in. A **workflow column** is different: its values come from a [workflow](/workflows) that runs once per row. For each row, the workflow reads the columns you choose as input, runs its blocks, and writes its results back into columns on that same row.
+
+This is what makes a table active. Instead of running a workflow by hand and pasting the results in, you attach the workflow to the table and it fills each row on its own. It works a bit like a spreadsheet macro that runs on every row, except each step is a full workflow.
+
+{/* VISUAL: side-by-side. Left: traditional enrichment (table → webhook → external service → manual write-back). Right: active table (one workflow column; data stays in place, the workflow runs per row in the grid). */}
+
+Here's an example. A table of companies has one column, `company`, that you type in. A workflow reads each company name and returns whether it's a qualified lead, the reason, and a confidence score. Those three values land in three new columns:
+
+```
+company │ qualified │ reason │ confidence
+───────────────┼───────────┼─────────────────────────┼───────────
+Acme Corp │ true │ Enterprise, 500+ seats │ 0.92
+Globex │ false │ Out of target market │ 0.41
+```
+
+## The parts of a workflow column
+
+### Workflow group
+
+A **workflow group** is the unit you configure: one workflow, plus how its inputs and outputs map to columns, plus what makes it run. One group can produce several result columns from a single run per row. In the example, one group runs the qualify workflow and fills `qualified`, `reason`, and `confidence` together.
+
+You set a group up in the column configuration sidebar, where you pick the workflow, map its inputs and outputs to columns, and set what it runs after.
+
+{/* VISUAL: column configuration sidebar. Workflow picker, input mappings (column → input field), output picker grouped by block name, "Run after" deps, "Auto-run" toggle. */}
+
+### Input columns
+
+**Input columns** are the columns whose per-row values feed the workflow. Each input mapping links one column to one input field on the workflow's [Start](/triggers/start) trigger. When the group runs on a row, that row's `company` value is read into the workflow's input, and the workflow reads it as ``.
+
+The workflow only sees the columns you mapped. The rest of the row is left untouched. Inputs are read-only during the run.
+
+### Output columns
+
+**Output columns** are plain columns that receive the workflow's results. Each output column is linked to one block output inside the workflow, picked by name: `qualified` is linked to the agent's `qualified` value, `reason` to its `reason`, and so on. The workflow runs once; every output you picked is written to its column. Outputs you didn't pick are discarded.
+
+{/* VISUAL: before/after. A plain `company` column, then the same table with `qualified` (boolean), `reason` (text), `confidence` (number) populated per row. */}
+
+### Run after
+
+**Run after** is the set of columns that must be filled before the group runs on a row. In the example, the group runs after `company`: a row with an empty `company` waits, and the moment `company` gets a value, that row becomes eligible.
+
+A dependency can be a typed column or another group's output column. That second case is what makes cascades work (below). At least one dependency is required when auto-run is on.
+
+### Auto-run
+
+**Auto-run** decides whether the group fires on its own. With auto-run on, a group runs a row as soon as that row's Run-after columns are filled, with no click needed. With auto-run off, the group is manual: it runs only when you trigger it.
+
+You trigger a group by hand from its column header menu:
+
+- **Run this row** runs the one row.
+- **Run all rows** runs every row, and re-runs rows that already finished.
+- **Run empty rows** runs only rows whose output columns are still empty.
+- **Run selected rows** runs the rows you've checked.
+
+Auto-run only ever runs rows it hasn't attempted yet. To re-run a row that already finished or errored, use **Run all rows**.
+
+### Execution status
+
+While a group works a row, its output cells show their state instead of a value:
+
+| State | Meaning |
+| --- | --- |
+| **Pending** | Waiting on a Run-after column that isn't filled yet. |
+| **Queued** | Eligible and waiting to start. |
+| **Running** | The workflow is executing for this row. |
+| **Error** | A block failed. The cell links to which block and why. |
+| **Cancelled** | The run was stopped before it finished. |
+| **Not found** | An enrichment finished but matched nothing for this row. |
+
+When a value arrives, it replaces the badge. Cells that finish stay filled even while other blocks in the same group are still running on that row.
+
+{/* VISUAL: execution status badges in output columns: Running (spinner), Queued, Pending (tooltip "waiting on company"), Error (red), and a completed value. */}
+
+
+On error, the row stays in the **Error** state. Auto-run skips errored rows, so a failure doesn't loop. To retry, fix the input and use **Run all rows**, which re-runs regardless of the auto-run setting. A row is only ever worked by one run at a time, so re-running doesn't race.
+
+
+## Cascades
+
+Because a group can run after another group's output column, you can chain groups across the table. Each group fills its columns; the next group runs after those columns and fills the next set. This is a **cascade**.
+
+The example extends naturally: an **Enrich** group fills `industry` and `headcount` from `company`. A **Qualify** group runs after `industry` and fills `qualified`. An **Outreach** group runs after `qualified` and drafts an email. Each row advances through the groups independently, becoming eligible for the next group the moment its own Run-after columns are filled.
+
+{/* VISUAL: cascade diagram. Three group headers left to right (Enrich → Qualify → Outreach), arrows showing each group's output columns feeding the next group's Run-after. */}
+
+## When to use a workflow column
+
+Reach for a workflow column when you have a row-by-row job: enrich each record, classify each entry, score each lead. The work is the same shape on every row, and you want the results to live next to the source data.
+
+Use a [workflow on its own](/workflows) instead when the job isn't per-row: a one-off transform, an aggregation across many rows, or a real-time decision tied to a single request. To pull table data into a workflow rather than push workflow results into a table, see [using tables in workflows](/tables/using-in-workflows).
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json
index 84dac39482d..1c70c9820d7 100644
--- a/apps/docs/content/docs/en/tools/meta.json
+++ b/apps/docs/content/docs/en/tools/meta.json
@@ -1,4 +1,5 @@
{
+ "title": "Integrations",
"pages": [
"index",
"a2a",
@@ -34,7 +35,6 @@
"confluence",
"crowdstrike",
"cursor",
- "custom-tools",
"dagster",
"databricks",
"datadog",
@@ -104,7 +104,6 @@
"jira_service_management",
"kalshi",
"ketch",
- "knowledge",
"langsmith",
"launchdarkly",
"lemlist",
@@ -117,7 +116,6 @@
"mailchimp",
"mailgun",
"mem0",
- "memory",
"microsoft_ad",
"microsoft_dataverse",
"microsoft_excel",
diff --git a/apps/docs/content/docs/en/triggers/index.mdx b/apps/docs/content/docs/en/triggers/index.mdx
index e996a39bc27..91ed244549c 100644
--- a/apps/docs/content/docs/en/triggers/index.mdx
+++ b/apps/docs/content/docs/en/triggers/index.mdx
@@ -1,105 +1,71 @@
---
-title: Overview
-description: Triggers are the core ways to start Sim workflows
+title: Triggers
+description: How a workflow starts, from generic triggers to the integration catalog.
+pageType: concept
---
+import { Callout } from 'fumadocs-ui/components/callout'
import { Card, Cards } from 'fumadocs-ui/components/card'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'
-
+
-## Core Triggers
+A **trigger** is where a workflow begins. Every workflow has exactly one, and it decides both what starts the workflow and what input it receives. Triggers come in two kinds: generic triggers that work on their own, and integration triggers that fire on an event in an external service.
-Use the Start block for everything originating from the editor, deploy-to-API, or deploy-to-chat experiences. Other triggers remain available for event-driven workflows:
+## Generic triggers
+
+Three triggers work without any specific service, and they are the ones you reach for first.
- Unified entry point that supports editor runs, API deployments and chat deployments
+ The default entry point. Runs from the editor, an API deployment, or a chat deployment.
- Receive external webhook payloads
+ Runs on any inbound HTTP request to a URL Sim gives you.
- Cron or interval based runs
-
-
- Monitor RSS and Atom feeds for new content
-
-
- Monitor team Gmail and Outlook inboxes
+ Runs on a timer, set by a cron expression or an interval.
-## Quick Comparison
-
-| Trigger | Start condition |
-|---------|-----------------|
-| **Start** | Editor runs, deploy-to-API requests, or chat messages |
-| **Schedule** | Timer managed in schedule block |
-| **Webhook** | On inbound HTTP request |
-| **RSS Feed** | New item published to feed |
-| **Email Polling Groups** | New email received in team Gmail or Outlook inboxes |
-
-> The Start block always exposes `input`, `conversationId`, and `files` fields. Add custom fields to the input format for additional structured data.
-
-## Using Triggers
-
-1. Drop the Start block in the start slot (or an alternate trigger like Webhook/Schedule).
-2. Configure any required schema or auth.
-3. Connect the block to the rest of the workflow.
+## Integration triggers
-> Deployments power every trigger. Update the workflow, redeploy, and all trigger entry points pick up the new snapshot. Learn more in [Execution → Deployment Snapshots](/execution).
+An **integration trigger** starts a workflow when an event happens in an external service, and hands that event to the workflow. Sim has integration triggers for dozens of services, including [GitHub](/triggers/github), [Slack](/triggers/slack), [Gmail](/triggers/gmail), [Linear](/triggers/linear), [Stripe](/triggers/stripe), and [RSS feeds](/triggers/rss). Each fires on a specific event, like a GitHub push or a new email, and passes the event payload to your workflow. The full set is listed under Triggers in the reference.
-## Manual Run Priority
+## Comparison
-When you click **Run** in the editor, Sim automatically selects which trigger to run based on the following priority order:
+| Trigger | Starts the workflow when |
+| --- | --- |
+| **Start** | you run it in the editor, or call its API or chat deployment |
+| **Webhook** | an inbound HTTP request arrives |
+| **Schedule** | a timer fires, on a cron expression or an interval |
+| **Integration trigger** | its service event happens, like a GitHub push or a new email |
-1. **Start Block** (highest priority)
-2. **Schedule Triggers**
-3. **External Triggers** (webhooks, integrations like Slack, Gmail, Airtable, etc.)
+
+The Start trigger always exposes `input`, `conversationId`, and `files`; add fields to its input format for more structured data. Every trigger runs the active [deployment](/deployment), so redeploy after changing a workflow for triggers to pick up the new version.
+
-If your workflow has multiple triggers, the highest priority trigger will be used. For example, if you have both a Start block and a Webhook trigger, clicking Run will use the Start block.
+## Manual run priority
-**External triggers with mock payloads**: When external triggers (webhooks and integrations) are run manually, Sim automatically generates mock payloads based on the trigger's expected data structure. This ensures downstream blocks can resolve variables correctly during testing.
+When you click **Run** in the editor and a workflow has more than one trigger, Sim picks which to run by priority: the **Start** trigger first, then a **Schedule**, then **external triggers** (webhooks and integrations). So a workflow with both a Start trigger and a Webhook runs from Start when you click Run.
-## Email Polling Groups
+Running an external trigger by hand generates a mock payload based on the trigger's expected shape, so downstream blocks can resolve their references while you test, without waiting for a real event.
-Polling Groups let you monitor multiple team members' Gmail or Outlook inboxes with a single trigger. Requires a Team or Enterprise plan.
+## Email polling groups
-**Creating a Polling Group** (Admin/Owner)
+The Gmail and Outlook triggers can watch several team members' inboxes through a single trigger, called an **email polling group** (Team and Enterprise plans). It is a feature of those triggers, not a separate trigger type.
-1. Go to **Settings → Email Polling**
-2. Click **Create** and choose Gmail or Outlook
-3. Enter a name for the group
-
-**Inviting Members**
-
-1. Click **Add Members** on your polling group
-2. Enter email addresses (comma or newline separated, or drag & drop a CSV)
-3. Click **Send Invites**
-
-Invitees receive an email with a link to connect their account. Once connected, their inbox is automatically included in the polling group. Invitees don't need to be members of your Sim organization.
-
-This is separate from external workspace membership: polling group invitees are granting access to an inbox for a trigger, while external workspace members are collaborators with Read, Write, or Admin access to a workspace.
-
-**Using in a Workflow**
-
-When configuring an email trigger, select your polling group from the credentials dropdown instead of an individual account. The system creates webhooks for each member and routes all emails through your workflow.
+An admin creates a group under **Settings → Email Polling**, picks Gmail or Outlook, and invites members by email address. Each invitee gets a link to connect their own inbox, which then joins the group; they don't need to be members of your Sim organization. To use it, select the group from the credentials dropdown on an email trigger instead of a single account, and the trigger routes everyone's mail through the workflow. Inviting someone grants inbox access for the trigger only, which is separate from workspace membership.
+
diff --git a/apps/docs/content/docs/en/triggers/start.mdx b/apps/docs/content/docs/en/triggers/start.mdx
index 672da65024a..5ab88809ac1 100644
--- a/apps/docs/content/docs/en/triggers/start.mdx
+++ b/apps/docs/content/docs/en/triggers/start.mdx
@@ -44,7 +44,7 @@ Reference structured values downstream with expressions such as <start.
## How it behaves per entry point
-
+
When you click Run in the editor, the Start block renders the Input Format as a form. Default values make it easy to retest without retyping data. Submitting the form triggers the workflow immediately and the values become available on <start.fieldName> (for example <start.sampleField>).
@@ -64,13 +64,6 @@ Reference structured values downstream with expressions such as <start.
If you launch chat with additional structured context (for example from an embed), it merges into the corresponding <start.fieldName> outputs, keeping downstream blocks consistent with API and manual runs.
-
- Form deployments render the Input Format as a standalone, embeddable form page. Each field becomes a form input with appropriate UI controls—text inputs for strings, number inputs for numbers, toggle switches for booleans, and file upload zones for files.
-
- When a user submits the form, values become available on <start.fieldName> just like other entry points. The workflow executes with trigger type form, and submitters see a customizable thank-you message upon completion.
-
- Forms can be embedded via iframe or shared as direct links, making them ideal for surveys, contact forms, and data collection workflows.
-
## Referencing Start data downstream
diff --git a/apps/docs/content/docs/en/variables/index.mdx b/apps/docs/content/docs/en/variables/index.mdx
deleted file mode 100644
index d3543f368f7..00000000000
--- a/apps/docs/content/docs/en/variables/index.mdx
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: Variables
----
-
-import { Callout } from 'fumadocs-ui/components/callout'
-import { Card, Cards } from 'fumadocs-ui/components/card'
-import { FAQ } from '@/components/ui/faq'
-
-Sim has two systems for injecting dynamic values into your workflows: **workflow variables** for in-run state and **environment variables** for secrets and configuration.
-
-## Variable Syntax at a Glance
-
-| Syntax | What it references | Example |
-|--------|-------------------|---------|
-| `` | Workflow variable | `` |
-| `` | Nested property | `` |
-| `` | Block output | `` |
-| `` | Loop iteration (inside loop) | `` |
-| `` | Parallel instance (inside parallel) | `` |
-| `{{KEY}}` | Environment variable | `{{OPENAI_API_KEY}}` |
-
-Type `<` in any block text field to open the variable picker and browse available references.
-
-## Workflow Variables
-
-Workflow variables are a global store that any block can read or update during execution. They're defined in the **Variables** panel in the sidebar and support text, numbers, booleans, objects, and arrays.
-
-Key behaviors:
-- **Global scope**: Accessible from any block in the workflow
-- **Run-scoped persistence**: Changes during a run are visible to subsequent blocks, but each new execution resets variables to their initial values
-- **Nested access**: Use dot notation for object properties (``)
-- **Updated via the Variables block**: Use the [Variables block](/blocks/variables) to modify variable values mid-workflow
-
-
- Full guide on creating, accessing, and updating workflow variables
-
-
-## Environment Variables
-
-Environment variables store sensitive values like API keys, tokens, and configuration that should never appear in logs or be visible in the workflow canvas.
-
-### Creating Environment Variables
-
-1. Go to **Settings** in your workspace
-2. Open the **Secrets** tab
-3. Click **Add** and enter a key-value pair
-
-### Personal vs. Workspace
-
-| Scope | Visibility | Use case |
-|-------|-----------|----------|
-| **Workspace** | All workspace members, including external workspace members | Shared API keys, team configuration |
-| **Personal** | Only you | Your personal tokens, dev credentials |
-
-When both a workspace and personal variable share the same key, the workspace value takes precedence.
-
-### Using Environment Variables
-
-Reference them with double curly braces in any block field:
-
-```
-{{API_KEY}}
-```
-
-
- Environment variable names must start with a letter or underscore and contain only letters, numbers, and underscores (e.g., `MY_API_KEY`).
-
-
-### Environment Variables vs. Credentials
-
-| | Environment Variables | Credentials |
-|--|----------------------|-------------|
-| **Format** | Key-value string pairs | OAuth tokens, API keys with provider context |
-| **Syntax** | `{{KEY}}` | Selected via dropdown in block config |
-| **Best for** | Custom API keys, configuration values, feature flags | OAuth services (Slack, GitHub, Google), managed connections |
-| **Management** | Settings → Secrets | Settings → Credentials |
-
-Use environment variables when you have a raw API key or config value. Use [credentials](/credentials) when connecting to a service that needs OAuth or managed token refresh.
-
-## Name Conflicts
-
-If a workflow variable and a block output share the same name, Sim resolves the reference in a fixed priority order: loop and parallel context first, then workflow variables, then environment variables, then block outputs. To avoid confusion, use distinct names for your variables and blocks.
-
- syntax. Environment variables store sensitive configuration like API keys using {{KEY}} syntax. They never appear in logs and are managed at the workspace or personal level." },
- { question: "Can I use environment variables in the Function block?", answer: "Yes. Use the double curly brace syntax {{KEY}} directly in your code. The value is substituted before execution, so the actual secret never appears in logs or outputs." },
- { question: "How do I share an API key with my team?", answer: "Create a workspace-scoped environment variable in Settings → Secrets. All workspace members, including external workspace members, will be able to use it in their workflows via {{KEY}} syntax." },
- { question: "What happens if a variable name has spaces or mixed case?", answer: "Variable resolution is case-insensitive and ignores spaces. A variable named 'My Counter' can be referenced as or . However, using consistent naming (like camelCase) is recommended." },
- { question: "Can I reference environment variables in the Agent system prompt?", answer: "Yes. You can use {{KEY}} syntax in any text field, including system prompts, to inject environment variable values." },
-]} />
diff --git a/apps/docs/content/docs/en/variables/meta.json b/apps/docs/content/docs/en/variables/meta.json
deleted file mode 100644
index 00b2a1dc9e0..00000000000
--- a/apps/docs/content/docs/en/variables/meta.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "title": "Variables",
- "pages": ["index", "workflow-variables"],
- "defaultOpen": false
-}
diff --git a/apps/docs/content/docs/en/variables/workflow-variables.mdx b/apps/docs/content/docs/en/variables/workflow-variables.mdx
deleted file mode 100644
index 0cf4aa56613..00000000000
--- a/apps/docs/content/docs/en/variables/workflow-variables.mdx
+++ /dev/null
@@ -1,164 +0,0 @@
----
-title: Workflow Variables
----
-
-import { Callout } from 'fumadocs-ui/components/callout'
-import { Step, Steps } from 'fumadocs-ui/components/steps'
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
-import { Image } from '@/components/ui/image'
-import { Video } from '@/components/ui/video'
-import { FAQ } from '@/components/ui/faq'
-
-Variables in Sim act as a global store for data that can be accessed and modified by any block in your workflow, allowing you to store and share data across your workflow with global variables. They provide a powerful way to share information between different parts of your workflow, maintain state, and create more dynamic applications.
-
-
-
-
-
-
- Variables allow you to store and share data across your entire workflow, making it easy to
- maintain state and create complex, interconnected systems.
-
-
-## Overview
-
-The Variables feature serves as a central data store for your workflow, enabling you to:
-
-
-
- Store global data: Create variables that persist throughout workflow execution
-
-
- Share information between blocks: Access the same data from any block in your
- workflow
-
-
- Maintain workflow state: Keep track of important values as your workflow runs
-
-
- Create dynamic workflows: Build more flexible systems that can adapt based on
- stored values
-
-
-
-## Creating Variables
-
-To open the Variables panel, click **⋯ → Variables** in the top-right of the workflow editor.
-
-
-
-
-
-Each variable has:
-
-- **Name**: A unique identifier used to reference the variable
-- **Type**: The data type (Plain, Number, Boolean, Object, Array)
-- **Value**: The data stored in the variable
-
-
-
-
-
-## Accessing Variables
-
-Variables can be accessed from any block in your workflow using the variable dropdown. Simply:
-
-1. Type `<` in any text field within a block
-2. Browse the dropdown menu to select from available variables
-3. Select the variable you want to use
-
-
-
-
-
-
- You can also drag the connection tag into a field to open the variable dropdown and access
- available variables.
-
-
-## Variable Types
-
-Variables in Sim can store various types of data:
-
-
-
- ```
- "Hello, World!"
- ```
- Plain variables store strings of characters. They're useful for storing messages, names, and other text data.
-
-
- ```
- 42
- ```
- Number variables store numeric values that can be used in calculations or comparisons.
-
-
- ```
- true
- ```
- Boolean variables store true/false values, perfect for flags and condition checks.
-
-
- ```json
- {
- "name": "John",
- "age": 30,
- "city": "New York"
- }
- ```
- Object variables store structured data with properties and values.
-
-
- ```json
- [1, 2, 3, "four", "five"]
- ```
- Array variables store ordered collections of items.
-
-
-
-## Using Variables in Blocks
-
-When you access a variable from a block, you can:
-
-- **Read its value**: Use the variable's current value in your block's logic
-- **Modify it**: Update the variable's value based on your block's processing
-- **Use it in expressions**: Include variables in expressions and calculations
-
-## Variable Scope
-
-Variables in Sim have global scope, meaning:
-
-- They are accessible from any block in your workflow
-- Changes to variables persist throughout workflow execution
-- Variables start fresh from their defined values on each run. Changes during execution are visible within that run only
-
-## Best Practices
-
-- **Use Descriptive Names**: Choose variable names that clearly indicate what the variable represents. For example, use `userPreferences` instead of `up`.
-- **Document Your Variables**: Add descriptions to your variables to help other team members understand their purpose and usage.
-- **Consider Variable Scope**: Remember that variables are global and can be modified by any block. Design your workflow with this in mind to prevent unexpected behavior.
-- **Initialize Variables Early**: Set up and initialize your variables at the beginning of your workflow to ensure they're available when needed.
-- **Handle Missing Variables**: Always consider the case where a variable might not yet exist or might have an unexpected value. Add appropriate validation in your blocks.
-- **Limit Variable Count**: Keep the number of variables manageable. Too many variables can make your workflow difficult to understand and maintain.
-
- syntax. Environment variables (secrets) are workspace-level credentials referenced with {{KEY}} syntax, designed for sensitive values like API keys that should never appear in logs." },
- { question: "How are variables resolved during execution?", answer: "The execution engine uses a chain of resolvers that run in order: loop variables, parallel variables, workflow variables, environment variables, and then block references. When a block input contains a variable reference, the resolver matches it by normalized name (case-insensitive, spaces removed) or exact ID, then substitutes the resolved value before the block runs." },
- { question: "Can I use nested paths to access properties inside an object variable?", answer: "Yes. If your variable stores an object or array, you can use dot notation to access nested properties. For example, will navigate into the config object and return the retryCount value." },
- { question: "Do workflow variables persist between separate workflow runs?", answer: "Variables maintain their initial values as defined in the Variables panel. Each execution starts with those configured values. If a block modifies a variable during execution, that change is visible to subsequent blocks in the same run, but does not alter the saved initial value for future runs." },
- { question: "What happens if I reference a variable that does not exist?", answer: "If the resolver cannot find a matching variable, the raw reference string is left in place without substitution. This typically causes downstream blocks to receive unexpected input, so make sure all referenced variables are defined before running the workflow." },
- { question: "Can I store JSON objects or arrays as variable values?", answer: "Yes. Variables support text, numbers, booleans, JSON objects, and arrays. When the value is parsed for execution, the engine determines the type and resolves it accordingly, so downstream blocks receive the proper JavaScript object or array rather than a raw string." },
-]} />
diff --git a/apps/docs/content/docs/en/workflows/connections.mdx b/apps/docs/content/docs/en/workflows/connections.mdx
new file mode 100644
index 00000000000..ab82f24bf65
--- /dev/null
+++ b/apps/docs/content/docs/en/workflows/connections.mdx
@@ -0,0 +1,158 @@
+---
+title: Connections
+description: The syntax for referencing an earlier block's output and the shape of common block outputs.
+pageType: reference
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+A **connection** wires one block to the next and sets the order they run in. [How blocks pass data](/workflows/data-flow) covers the concept: once a block runs, its output is remembered under the block's name, and any later block reads it by reference. This page is the reference for the **connection tag** syntax and the output shapes you'll reach into.
+
+## Tag syntax
+
+A connection tag references a value from an earlier block's output:
+
+```
+
+```
+
+- `blockName` is the name of the source block. Block names are normalized before matching, so they're lowercased and spaces are removed. `` and `` resolve to the same block.
+- `path.to.data` is the path to the value inside that block's output. The field path is case-sensitive.
+
+You rarely type a tag by hand. In any input field, type `<` to open a dropdown of the values available from earlier blocks and pick one, or drag a value from a connected block straight into the field.
+
+## Nested and array fields
+
+Chain dot notation to reach into objects, and use bracket indices for arrays. Both combine in a single path:
+
+```
+
+
+
+```
+
+The resolver walks the path at runtime and substitutes the value. Multiple levels of indexing like `items[0][1]` work too.
+
+## Using tags in text and code
+
+Tags resolve at runtime and can sit anywhere in a field, mixed with static text:
+
+```javascript
+// In text
+"The user's name is "
+
+// In JSON
+{
+ "userName": "",
+ "orderTotal":
+}
+
+// In a Function block
+const greeting = `Hello, ${""}!`
+const total = * 1.1
+```
+
+Values are formatted to fit their context. In a [Function](/blocks/function) block, a resolved value becomes a code literal, so strings are quoted, objects are JSON, and `null` stays `null`, ready to drop into JavaScript or Python. In other blocks, objects are JSON-stringified and primitives become plain strings.
+
+
+In a numeric context, confirm the referenced value is actually a number. A tag that resolves to text will not behave as a number.
+
+
+When a referenced block didn't run on the current path, for example a block on an unselected branch, its tag resolves to an empty value. In most blocks that's an empty string; in Function blocks it's `null`.
+
+## Common block outputs
+
+A tag's path depends on what the source block produced. These are the standard shapes for the blocks you'll reference most. The output panel shows the live structure for any block.
+
+
+
+ ```json
+ {
+ "content": "The generated text response",
+ "model": "gpt-4o",
+ "tokens": { "prompt": 120, "completion": 85, "total": 205 },
+ "toolCalls": [],
+ "cost": []
+ }
+ ```
+
+ `content` is the main response. `tokens` is an object of usage counts. `toolCalls` and `cost` are present when the agent used tools. With a response format configured, the output matches your schema instead of this shape.
+
+
+ ```json
+ {
+ "data": "Response body",
+ "status": 200,
+ "headers": { "content-type": "application/json" }
+ }
+ ```
+
+ `data` is the response body and can be any type. `status` is the HTTP status code. `headers` holds the response headers.
+
+
+ ```json
+ {
+ "result": "Function return value",
+ "stdout": "Console output"
+ }
+ ```
+
+ `result` is whatever your function returned and can be any type. `stdout` captures anything the code logged.
+
+
+ ```json
+ {
+ "conditionResult": true,
+ "selectedPath": {
+ "blockId": "2acd9007-27e8-4510-a487-73d3b825e7c1",
+ "blockType": "agent",
+ "blockTitle": "Follow-up Agent"
+ },
+ "selectedOption": "condition-1"
+ }
+ ```
+
+ `conditionResult` is the boolean result. `selectedPath` describes the next block. `selectedOption` is the ID of the matched condition.
+
+
+ ```json
+ {
+ "content": "Routing decision",
+ "model": "gpt-4o",
+ "tokens": { "prompt": 120, "completion": 85, "total": 205 },
+ "selectedPath": {
+ "blockId": "2acd9007-27e8-4510-a487-73d3b825e7c1",
+ "blockType": "agent",
+ "blockTitle": "Customer Service Agent"
+ }
+ }
+ ```
+
+ `content` is the routing decision text. `selectedPath` describes the chosen destination block.
+
+
+ ```json
+ {
+ "content": "Evaluation summary",
+ "model": "gpt-5",
+ "tokens": { "prompt": 120, "completion": 85, "total": 205 },
+ "metric1": 8.5,
+ "metric2": 7.2
+ }
+ ```
+
+ `content` summarizes the evaluation. Each metric you defined appears as its own field with a numeric score.
+
+
+
+A Function's `result`, an API's `data`, and an Agent with a response format all return whatever your code, the remote service, or your schema produced, so check the output panel during development to confirm the path you're referencing.
+
+## Next
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workflows/data-flow.mdx b/apps/docs/content/docs/en/workflows/data-flow.mdx
new file mode 100644
index 00000000000..52fbf678715
--- /dev/null
+++ b/apps/docs/content/docs/en/workflows/data-flow.mdx
@@ -0,0 +1,71 @@
+---
+title: How blocks pass data
+description: What a block's output is, how blocks reference earlier outputs, and the data types you'll work with.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { WorkflowPreview, OutputBundle, CLASSIFY_REPLY_WORKFLOW } from '@/components/workflow-preview'
+
+Most blocks need a value that an earlier block produced. A block gets it by referencing that block's output by name. This page covers three things: what an output is and where it lives, how a block references one, and the types of values you'll find inside.
+
+
+
+In this workflow, Classify reads the message from Start, and Reply reads the classification from Classify.
+
+## What an output is
+
+When a block runs, Sim keeps its result under the block's name for the rest of the run. That stored result is the block's **output**, and any later block can read it.
+
+An output is usually a set of named values, not a single thing. You read one by its key: `` is the `content` value of the block named `classify`.
+
+
+
+Different blocks produce different values. An [Agent](/blocks/agent) keeps its `content`; an [API](/blocks/api) keeps the `data` it received; a Table block keeps a `rowCount` and the rows it read, reached with ``.
+
+
+A block's output is not the same as the **workflow's** output. Every block has its own, kept under its own name. The workflow's output is simply one of them: whatever the last block produced.
+
+
+## How a block references an output
+
+A block's inputs are its **parameters**: the fields you fill in, like an Agent's model and prompt. In any parameter you can insert a **connection tag** to pull in an earlier output instead of typing a fixed value. The `` in Classify's prompt means "use whatever Start received here."
+
+
+
+A block can reference any output that already exists by the time it runs, meaning any block before it on its path (see [how workflows run](/workflows/how-it-runs)). You rarely type a tag by hand: wherever a parameter accepts one, the builder lists the available outputs and you pick the value you want.
+
+## Data types
+
+Each value inside an output has a type, shown next to it in the output panel. The type tells you what you can do with the value: index into an array, read a field from an object, compare a number.
+
+| Type | What it is | Example |
+| --- | --- | --- |
+| `string` | Text | `"Billing issue"` |
+| `number` | A numeric value | `248` |
+| `boolean` | `true` or `false` | `true` |
+| `object` | A set of named fields | `{ category: "billing", urgency: "high" }` |
+| `array` | An ordered list of values | `["billing", "urgent"]` |
+| `null` | No value | `null` |
+
+A file shows up as an `object` carrying the file's details, like its name and URL. When a value isn't the type the next step needs, reshape it in a [Function](/blocks/function) block, which runs a short snippet of code and stores the result as its own output.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workflows/how-it-runs.mdx b/apps/docs/content/docs/en/workflows/how-it-runs.mdx
new file mode 100644
index 00000000000..dff3a02af75
--- /dev/null
+++ b/apps/docs/content/docs/en/workflows/how-it-runs.mdx
@@ -0,0 +1,52 @@
+---
+title: How workflows run
+description: How Sim orders the blocks, runs independent ones in parallel, and follows branches.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { Image } from '@/components/ui/image'
+
+When you run a workflow, Sim works out the order from the [connections](/workflows/connections): a block runs as soon as the blocks it depends on have finished. You never set the order by hand; the way blocks are wired implies it.
+
+## Independent blocks run in parallel
+
+Two blocks that don't depend on each other run at the same time. There's nothing to configure. If neither block is downstream of the other, Sim runs them together.
+
+
+
+Here the Customer Support and Deep Researcher agents both run right after the Start trigger, instead of one waiting on the other.
+
+## A block waits for all its inputs
+
+When several blocks feed into one, that block waits for all of them to finish, then runs once with each of their outputs available to read. You don't merge them yourself.
+
+
+
+The Function block here runs after both agents complete, with both of their outputs ready.
+
+## Branches follow one path
+
+A workflow can split. A [Condition](/blocks/condition) block branches on an explicit rule; a [Router](/blocks/router) block lets a model choose the path. Only the branch that is taken runs. A block on a branch that didn't run produces no output, which is why a [connection tag](/workflows/connections) pointing at it comes back empty.
+
+
+
+To repeat work, a [Loop](/blocks/loop) block runs its inner blocks over a list or a count, and a [Parallel](/blocks/parallel) block runs them for several items at once.
+
+
+A workflow can call other workflows, through a Workflow block, an MCP tool, or an API block. Sim tracks the call chain and stops a run that exceeds 25 hops, so workflows that call each other can't loop forever.
+
+
+## Watching a run
+
+While a workflow runs, the editor shows each block's state live: queued, running, done, or errored. A failed block stops its own path but leaves independent paths running. Every run is recorded, so you can open the [logs](/logs-debugging) to see what each block received and returned after it finishes.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workflows/index.mdx b/apps/docs/content/docs/en/workflows/index.mdx
new file mode 100644
index 00000000000..630584ca8e0
--- /dev/null
+++ b/apps/docs/content/docs/en/workflows/index.mdx
@@ -0,0 +1,83 @@
+---
+title: Overview
+description: A workflow is a visual program made of blocks, a saved procedure your AI systems run.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { WorkflowPreview, CLASSIFY_WORKFLOW } from '@/components/workflow-preview'
+
+Your Sim workspace is where your AI systems live. A system is made of two things. **Workflows** are the procedures it runs. **Resources** are the data those procedures work with: tables, knowledge bases, and files.
+
+A workflow is a visual program made of blocks. Like a recipe, it's a fixed set of steps you write once and run again and again, each time with new input. Each block does one step of work, and connections set the order the blocks run in.
+
+Here's a simple one. It takes an incoming customer message, classifies its category and urgency, and returns the result:
+
+
+
+## The parts of a workflow
+
+### Trigger
+
+A **trigger** is where a workflow begins and what it hands in. Every workflow has exactly one. The [Start](/triggers/start) trigger takes input directly, which is what you use while building. In production you swap in a [chat](/triggers/start), [webhook](/triggers/webhook), [schedule](/triggers/schedule), or API trigger, and the downstream blocks don't change.
+
+
+
+In our example, the Start trigger receives the customer message. Later blocks read it by name, as ``.
+
+### Block
+
+A **block** is a single step, and each does one thing: an [Agent](/blocks/agent) reasons with a model, a [Function](/blocks/function) runs code, a [Condition](/blocks/condition) branches, a [Loop](/blocks/loop) repeats. Some blocks are deterministic (Function, Condition); others are model-driven (Agent) and can vary run to run. That difference is the first thing to know when debugging.
+
+
+
+Our example has one Agent block, configured with a model and a prompt, that reads the message and returns a classification.
+
+
+A block is not the same as a tool. A **tool** is a capability an agent can call during a step: send a Slack message, search a knowledge base, run a snippet of code. An [Agent](/blocks/agent) block decides which tools to call and when. Blocks are the workflow's steps; tools are the actions an agent takes inside one.
+
+
+### Connection
+
+A **connection** wires one block to the next and sets the execution order: the block at the arrow's head runs after the one at its tail. Once a block has run, the blocks after it can read its output by reference.
+
+
+
+You read an earlier output with a **connection tag**, written ``: name the block, then the value you want. The Agent's prompt reads the message with ``; a later block could read the Agent's answer with ``.
+
+Most workflow issues are data issues, not crashed blocks: a reference points at a value that isn't there, or a block on the path didn't run. See [how blocks pass data](/workflows/data-flow) for outputs, references, and types.
+
+### Output
+
+An **output** is what a block produces; later blocks read it through connection tags. By default the workflow's output is its **last block's** output. In our example that's the Agent's `{ category, urgency }`. There's no separate return step.
+
+
+
+On reuse, the consumer picks which outputs it wants by name: a [chat deployment](/deployment/chat), a [table column](/tables/workflow-columns), or an [API call](/deployment/api) each select block outputs individually. It's the same idea as connection tags, applied at the workflow's edge. (For precise HTTP control, add a [Response block](/blocks/response).)
+
+## How it runs
+
+When a workflow runs, blocks execute in dependency order: a block runs as soon as the blocks it depends on have finished, so independent branches run in parallel. Conditions, loops, and parallel blocks change the path data takes.
+
+
+
+## Workflows in context
+
+A workflow is where the rest of the workspace becomes behavior. On their own, tables, knowledge bases, files, and integrations are just resources. Workflows are where they *do* something.
+
+{/* VISUAL: system-context diagram. Mothership builds; tables/KBs/files/integrations feed; deployments expose; logs verify. */}
+
+- **Mothership** builds and edits workflows in natural language.
+- **Tables, knowledge bases, files, and integrations** feed data, memory, artifacts, and actions into a workflow.
+- **Deployments** expose a workflow as an API, chat, or MCP server.
+- **Logs** record every run so you can verify what happened, step by step.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workflows/variables.mdx b/apps/docs/content/docs/en/workflows/variables.mdx
new file mode 100644
index 00000000000..33147de22c3
--- /dev/null
+++ b/apps/docs/content/docs/en/workflows/variables.mdx
@@ -0,0 +1,110 @@
+---
+title: Variables
+description: Define reusable workflow variables referenced with angle brackets and environment variables referenced with double curly braces.
+pageType: reference
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
+
+A **variable** is a value you set yourself and reuse across a workflow. Sim has two kinds. **Workflow variables** hold data during a run, like a counter or a config object, and you reference them with ``. **Environment variables** hold secrets and configuration, like API keys, and you reference them with `{{KEY}}`.
+
+A variable is different from a **connection tag**. A variable is a value you define; a connection tag like `` reads the output a block produced earlier in the run. See [how blocks pass data](/workflows/data-flow) for connection tags.
+
+## Syntax at a glance
+
+| Syntax | References | Example |
+|--------|-----------|---------|
+| `` | A workflow variable | `` |
+| `` | A nested property of an object variable | `` |
+| `{{KEY}}` | An environment variable | `{{OPENAI_API_KEY}}` |
+| `` | A block output (connection tag) | `` |
+
+Type `<` in any block text field to open the picker and browse the variables and outputs you can reference.
+
+## Workflow variables
+
+Workflow variables are a global store any block can read or update during a run. Open the panel with **⋯ → Variables** in the top-right of the editor. Each variable has a **name**, a **type**, and a **value**.
+
+Reference one anywhere a field accepts input. For an object or array variable, use dot notation to reach a nested value, like ``. Name matching ignores case and spaces, so a variable named `My Counter` resolves from ``. Consistent names like `camelCase` are still the clearest.
+
+### Types
+
+
+
+ ```
+ "Hello, World!"
+ ```
+ Text, for messages, names, and other strings.
+
+
+ ```
+ 42
+ ```
+ A numeric value for calculations or comparisons.
+
+
+ ```
+ true
+ ```
+ A `true`/`false` flag.
+
+
+ ```json
+ { "name": "John", "age": 30 }
+ ```
+ Structured data with named fields, reached with dot notation.
+
+
+ ```json
+ [1, 2, 3, "four", "five"]
+ ```
+ An ordered list of values.
+
+
+
+### Scope
+
+Workflow variables are global: every block in the workflow can read and modify them. Use the [Variables block](/blocks/variables) to update a value mid-run.
+
+Each run starts fresh from the values defined in the panel. A change made during a run is visible to later blocks in that same run, but it never alters the saved initial value for future runs.
+
+## Environment variables
+
+Environment variables store sensitive values like API keys, tokens, and configuration that should never appear in logs or on the canvas. Create them under **Settings → Secrets** by adding a key-value pair.
+
+Reference them with double curly braces in any block field, including Agent system prompts and Function block code. The value is substituted before the block runs, so the secret never appears in logs or outputs.
+
+```
+{{API_KEY}}
+```
+
+
+ Environment variable names must start with a letter or underscore and contain only letters, numbers, and underscores, like `MY_API_KEY`.
+
+
+### Personal vs. workspace
+
+| Scope | Visible to | Use for |
+|-------|-----------|---------|
+| **Workspace** | All workspace members, including external members | Shared API keys, team configuration |
+| **Personal** | Only you | Your personal tokens, dev credentials |
+
+When a workspace and a personal variable share a key, the workspace value wins.
+
+### Versus credentials
+
+Environment variables hold raw string values you reference with `{{KEY}}`. [Credentials](/credentials) hold OAuth tokens and managed connections for services like Slack, GitHub, and Google, selected from a dropdown in a block's config. Use an environment variable for a raw API key or config value; use a credential when a service needs OAuth or managed token refresh.
+
+## Name conflicts
+
+When a reference could match more than one thing, Sim resolves it in a fixed order: loop and parallel context first, then workflow variables, then environment variables, then block outputs. If nothing matches, the raw reference is left in place unsubstituted, which usually breaks the block that reads it. Use distinct names for variables and blocks to avoid ambiguity.
+
+## Next
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workspaces/fundamentals.mdx b/apps/docs/content/docs/en/workspaces/fundamentals.mdx
new file mode 100644
index 00000000000..ef99848c01c
--- /dev/null
+++ b/apps/docs/content/docs/en/workspaces/fundamentals.mdx
@@ -0,0 +1,87 @@
+---
+title: Workspace fundamentals
+description: A workspace is the container that holds your workflows and resources and scopes who can access them.
+pageType: concept
+---
+
+import { Callout } from 'fumadocs-ui/components/callout'
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+A workspace is the container for one set of AI systems. It holds the workflows you build and the resources they use: tables, files, knowledge bases, integrations, and secrets. It also draws the boundary for access. Every resource belongs to exactly one workspace, and the people who can see those resources are the members of that workspace.
+
+Think of a workspace like a project folder, but for AI systems. Open it and you find everything one team needs in one place: the procedures, the data, the connected accounts, the run history, and the settings that govern them. Nothing crosses the boundary, so a workflow in one workspace cannot read a table in another.
+
+{/* VISUAL: nesting diagram. Outer ring: user or organization. Middle ring: workspace (the boundary). Inside: workflows, tables, files, knowledge bases, integrations, secrets. Members with permission levels attached at the workspace ring. */}
+
+## What a workspace contains
+
+The sidebar is the anatomy of a workspace. Each section is a kind of resource scoped to it:
+
+{/* VISUAL: the workspace sidebar with sections labeled: Workflows, Tables, Files, Knowledge Base, Scheduled Tasks, Logs, Settings. Each row shows one example item. */}
+
+### Workflows
+
+A **workflow** is a saved, repeatable procedure made of blocks: the primary resource in a workspace. You edit it, deploy it to surfaces like an API or a chat, and version it. See [Workflows](/workflows) for the full model.
+
+### Tables
+
+A **table** is structured data scoped to the workspace, used as a source or an output inside workflows.
+
+### Files
+
+A **file** is a document or binary stored in the workspace, readable by workflows and organized into folders.
+
+### Knowledge bases
+
+A **knowledge base** is a collection of documents or structured data that workflows search to give a model context at run time.
+
+### Integrations
+
+An **integration** is a connected account for a third-party service (Gmail, Slack, GitHub, and so on), scoped to the workspace. Each carries its own access control so a team shares one connection. See [Integrations](/integrations).
+
+### Secrets
+
+A **secret** is an API key or environment variable stored securely in the workspace. Secrets split into two scopes: **Workspace** secrets are shared with the workspace, and **Personal** secrets are private to you. See [Secrets](/credentials).
+
+### Logs
+
+A **log** is the execution trace of one workflow run: the trigger, the blocks that ran, and each block's input, output, and error. Logs are scoped to the workspace and are how you verify what happened.
+
+
+**Deployments** are not a sidebar section. A deployment is a versioned snapshot of one workflow, published for outside use through an API, chat, or MCP server. Editing a workflow does not change a live deployment until you promote the new version, and rollback means promoting an earlier one. See [Deployments](/deployment).
+
+
+## The boundary
+
+Scoping to the workspace is what makes the boundary useful, because access, billing, and operations all follow the same edge.
+
+- **Access.** Membership is granted per workspace. A member sees every resource in the workspace at the level their permission allows.
+- **Settings.** Each workspace carries its own configuration: integrations, secrets, access control, API keys, and more. The Settings page lists the full menu.
+- **Isolation.** Resources never span workspaces. To reuse a workflow elsewhere, you move or copy it into that workspace.
+
+Members join a workspace with one of three **permission levels**: **Read**, **Write**, or **Admin** (the creator is **Owner**). Read can view, Write can build and run, Admin can also manage members and settings. See [Roles and permissions](/permissions/roles-and-permissions) for the full breakdown.
+
+{/* VISUAL: organization → workspace → resources nesting, with members and their permission levels attached at the workspace ring. */}
+
+## Personal and organization workspaces
+
+Most workspaces are one of two kinds.
+
+A **personal workspace** lives under your own account. Use it for experimentation and individual work. Your plan sets how many you can create.
+
+An **organization workspace** (also called a shared workspace) lives under an organization, available on Team and Enterprise plans. You invite multiple members, each with a permission level. Internal members join the organization and count toward its seat total. External members keep their own organization membership and do not consume a seat, which is how partners and clients get access. For teams and enterprises, this workspace becomes the deliverable, the app the customer uses, owns, and maintains.
+
+A third kind, `grandfathered_shared`, exists for legacy accounts. Its invitation and billing rules differ from the two above; you will not create one.
+
+
+Plan limits, seat counts, and the internal-versus-external distinction live in [Roles and permissions](/permissions/roles-and-permissions). This page covers what a workspace is, not how billing works.
+
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/content/docs/en/workspaces/organization.mdx b/apps/docs/content/docs/en/workspaces/organization.mdx
new file mode 100644
index 00000000000..008efb98943
--- /dev/null
+++ b/apps/docs/content/docs/en/workspaces/organization.mdx
@@ -0,0 +1,78 @@
+---
+title: Organizing a workspace
+description: Folders, colors, and naming conventions for keeping a growing workspace understandable.
+pageType: concept
+---
+
+import { Card, Cards } from 'fumadocs-ui/components/card'
+
+A **folder** is a container in the sidebar that groups workflows. It is the primary way you organize a [workspace](/workspaces/fundamentals) once it holds more than a handful of workflows. Folders work like folders in a desktop file system: they nest, they collapse, and you arrange them by convention so the structure tells you where things live.
+
+A flat list of twenty workflows is hard to scan, but grouping the same twenty under three or four top-level folders gives you a map of where everything lives.
+
+{/* VISUAL: before/after sidebar. Left: a flat list of ~20 workflows, no grouping. Right: the same workflows under 3-4 top-level color-coded folders ("Internal", "Customer-Facing", "Ops"), some expanded to show nested subfolders. */}
+
+## The parts of a folder
+
+Here's an example: a folder named **Customer Deployments**, colored red, holding five workflows and two subfolders.
+
+### Name
+
+A **name** is the label you give a folder. It is plain text with no enforced format, so the convention is yours to set. Pick names that read as categories, not as one-off labels: `Internal`, `Customer-Facing`, `Ops`. Our example folder is named `Customer Deployments`. Naming is covered in [Conventions](#conventions) below.
+
+{/* VISUAL: a single sidebar folder row showing the expand chevron, color dot, and name "Customer Deployments". */}
+
+### Color
+
+A **color** is a hex value assigned to a folder for visual grouping, shown as a dot next to the name. It defaults to gray (`#6B7280`) and you can change it from the folder's menu. Color is the fastest way to read the sidebar at a glance. Reserve one color per top-level category (red for production, gray for scratch work) so you can find the right branch before reading a single name. Our example is red (`#EF4444`).
+
+{/* VISUAL: a short vertical stack of folders with distinct color dots: red "Production", gray "Internal", another color for "Customer-Facing", showing color as the grouping signal. */}
+
+### Nesting
+
+A folder can sit inside another folder. The inner one is a **subfolder**, and the structure is a tree: a top-level folder has no parent, a subfolder points at the folder that contains it, and that chain can go as deep as you need. Our example, `Customer Deployments`, holds two subfolders and itself sits under a `Production` folder.
+
+Lead with shallow trees. Two or three levels (`Production` > `Customer A` > `Deployments`) stay readable. Go deeper than that and you end up scrolling the sidebar instead of scanning it.
+
+{/* VISUAL: a three-level nested tree: "Production" (red, top level) > "Customer A" (yellow) > "Deployments" (purple), each row indented one step, showing the parent-to-child chain. */}
+
+### Order
+
+Folders display in a set **order**, top to bottom, that you control by dragging them in the sidebar. Drag a folder up or down to reorder it within its level, or drag it onto another folder to move it inside as a subfolder. Order is a convention too: put the folders a team touches daily at the top.
+
+### Locking
+
+A **locked** folder is read-only: its workflows can be viewed but not edited. Locking is off by default. Lock a `Production` folder so members can open and run its workflows without changing them by accident. Locking a folder also locks everything inside it, so a locked parent protects its subfolders and their workflows in one move. Who can lock and unlock follows the workspace [roles and permissions](/permissions/roles-and-permissions).
+
+{/* VISUAL: the folder context menu open on a folder row, showing the options: rename, change color, lock, duplicate, export, new subfolder, delete. */}
+
+### Archiving
+
+**Archiving** a folder removes it from your active sidebar without deleting it. An archived folder drops out of the normal view, and you restore it when you need it again. Use archiving for cleanup: a finished customer engagement or a retired experiment leaves the sidebar but stays recoverable. There is no permanent hard-delete in the folder menu, so archiving is the safe way to get something out of the way.
+
+## Conventions
+
+Naming conventions make the structure legible to someone who did not build it. Nothing here is enforced, so the value comes from applying one rule consistently across the workspace.
+
+- **Group by audience or function at the top level.** A common split is `Internal`, `Customer-Facing`, and `Ops`. Someone new can find the right branch from the top-level names alone.
+- **Name folders as categories, workflows as actions.** A folder is a noun (`Billing`); a workflow is a thing it does (`Send overdue reminder`). The folder path plus the workflow name should read as a sentence.
+- **Use color for the top level, names for everything below.** Color carries the coarse grouping; names carry the detail. Mixing both at every level turns into noise.
+- **Mirror the convention everywhere.** The same category words you use for folders are worth reusing for [tables](/workspaces/fundamentals), [secrets](/credentials), and [integrations](/integrations), so a team learns one vocabulary instead of three.
+
+## One workspace or several
+
+Folders organize within a workspace. A separate workspace draws a hard boundary: resources never cross it, and access is granted per workspace. Reach for a new workspace when you need that boundary, not just tidier grouping.
+
+- **Group in folders** when everything belongs to the same team and the same access rules, and you only want it easier to navigate.
+- **Split into workspaces** when a set of work needs its own members, its own integrations and secrets, or its own isolation. The classic case is one workspace per customer, where the workspace itself is the deliverable the customer owns.
+
+See [Workspace fundamentals](/workspaces/fundamentals) for what the boundary scopes and [Roles and permissions](/permissions/roles-and-permissions) for how members and seats work across workspaces.
+
+## Next
+
+
+
+
+
+
+
diff --git a/apps/docs/lib/source.ts b/apps/docs/lib/source.ts
index 430bb038a13..d3f3682603f 100644
--- a/apps/docs/lib/source.ts
+++ b/apps/docs/lib/source.ts
@@ -92,10 +92,14 @@ export const source = loader(
}
)
+/** Diátaxis page type surfaced as a badge near the page title. */
+export type DocsPageType = 'tutorial' | 'guide' | 'reference' | 'concept'
+
/** Full page data type including MDX content and metadata */
export type PageData = DocData &
DocMethods & {
title: string
description?: string
full?: boolean
+ pageType?: DocsPageType
}
diff --git a/apps/docs/next.config.ts b/apps/docs/next.config.ts
index f3a1aad5d89..39731da4cec 100644
--- a/apps/docs/next.config.ts
+++ b/apps/docs/next.config.ts
@@ -19,6 +19,38 @@ const config: NextConfig = {
destination: '/introduction',
permanent: true,
},
+ // building-agents/agents merged into the building-agents overview
+ { source: '/building-agents/agents', destination: '/building-agents', permanent: true },
+ // form deployment removed
+ { source: '/deployment/form', destination: '/deployment', permanent: true },
+ // copilot deprecated and removed
+ { source: '/copilot', destination: '/mothership', permanent: true },
+ { source: '/copilot/:path*', destination: '/mothership', permanent: true },
+ // connections/* and variables/* collapsed into single pages under workflows/
+ { source: '/connections', destination: '/workflows/connections', permanent: true },
+ { source: '/connections/:path*', destination: '/workflows/connections', permanent: true },
+ { source: '/variables', destination: '/workflows/variables', permanent: true },
+ { source: '/variables/:path*', destination: '/workflows/variables', permanent: true },
+ // capabilities/* renamed to building-agents/*
+ { source: '/capabilities', destination: '/building-agents', permanent: true },
+ { source: '/capabilities/agents', destination: '/building-agents/agents', permanent: true },
+ {
+ source: '/capabilities/choosing',
+ destination: '/building-agents/choosing',
+ permanent: true,
+ },
+ // execution/* was broken up; redirect old URLs to their new homes
+ { source: '/execution', destination: '/workflows', permanent: true },
+ { source: '/execution/index', destination: '/workflows', permanent: true },
+ { source: '/execution/basics', destination: '/workflows/how-it-runs', permanent: true },
+ { source: '/execution/files', destination: '/files/passing-files', permanent: true },
+ { source: '/execution/logging', destination: '/logs-debugging/logging', permanent: true },
+ { source: '/execution/costs', destination: '/costs', permanent: true },
+ { source: '/execution/api', destination: '/api-reference/getting-started', permanent: true },
+ { source: '/execution/api-deployment', destination: '/deployment/api', permanent: true },
+ { source: '/execution/chat', destination: '/deployment/chat', permanent: true },
+ { source: '/execution/form', destination: '/deployment/form', permanent: true },
+ { source: '/mcp/deploy-workflows', destination: '/deployment/mcp', permanent: true },
]
},
async rewrites() {
diff --git a/apps/docs/package.json b/apps/docs/package.json
index 49f658b42a5..5dafcf46383 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -32,7 +32,9 @@
"react": "19.2.4",
"react-dom": "19.2.4",
"shiki": "4.0.0",
- "tailwind-merge": "^3.0.2"
+ "tailwind-merge": "^3.0.2",
+ "reactflow": "^11.11.4",
+ "framer-motion": "^12.5.0"
},
"devDependencies": {
"@sim/tsconfig": "workspace:*",
diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts
index d2931dda32b..6a03ead5d0a 100644
--- a/apps/docs/source.config.ts
+++ b/apps/docs/source.config.ts
@@ -1,8 +1,18 @@
-import { defineConfig, defineDocs } from 'fumadocs-mdx/config'
+import { defineConfig, defineDocs, frontmatterSchema } from 'fumadocs-mdx/config'
+import { z } from 'zod'
+/**
+ * Diátaxis page type — an internal authoring taxonomy surfaced to readers as a
+ * small badge near the page title. Optional so existing pages render unchanged
+ * until backfilled. Only collections may be exported from this file, so the
+ * shared type lives in `@/lib/source` (`DocsPageType`).
+ */
export const docs = defineDocs({
dir: 'content/docs',
docs: {
+ schema: frontmatterSchema.extend({
+ pageType: z.enum(['tutorial', 'guide', 'reference', 'concept']).optional(),
+ }),
postprocess: {
includeProcessedMarkdown: true,
},
diff --git a/bun.lock b/bun.lock
index 2a293215c7e..5c99276b022 100644
--- a/bun.lock
+++ b/bun.lock
@@ -25,6 +25,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"drizzle-orm": "^0.45.2",
+ "framer-motion": "^12.5.0",
"fumadocs-core": "16.8.5",
"fumadocs-mdx": "14.3.2",
"fumadocs-openapi": "10.8.1",
@@ -35,6 +36,7 @@
"postgres": "^3.4.5",
"react": "19.2.4",
"react-dom": "19.2.4",
+ "reactflow": "^11.11.4",
"shiki": "4.0.0",
"tailwind-merge": "^3.0.2",
},