# How the Router Handler Implements Conditional Workflow Branching in simstudioai/sim

> Discover how the router handler in simstudioai/sim enables conditional workflow branching by checking user permissions against a write-actions registry for secure operation execution.

- Repository: [Sim/sim](https://github.com/simstudioai/sim)
- Tags: internals
- Published: 2026-05-02

---

**The router handler implements conditional workflow branching by evaluating user permissions against a static write-actions registry, allowing the workflow to proceed only when the caller has sufficient privileges for the requested operation.**

In the simstudioai/sim codebase, the Server-Tool Router serves as the gatekeeper for all Copilot-generated tool requests. Located at [`apps/sim/lib/copilot/tools/server/router.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/copilot/tools/server/router.ts), this handler determines whether a workflow continues down the execution path or terminates early with a permission error.

## The Routing Architecture

When a tool request arrives, the router follows a strict evaluation sequence to determine the execution branch. The process begins by looking up the requested tool in the `serverToolRegistry`, then extracting the specific action from the payload via `payload.operation` or `payload.action`.

The branching decision hinges on four key components working together:

- **`WRITE_ACTIONS`** (lines 55-101): A static mapping that defines which tools require write permissions for specific actions
- **`isWritePermission`** (lines 103-105): A helper that validates if the user's permission level is `write` or `admin`
- **`isActionAllowed`** (lines 107-118): The core permission evaluation logic that checks if an action requires elevated privileges
- **`routeExecution`**: The main entry point where the conditional branch is enforced

## Permission-Based Branching Logic

The conditional branching operates as a binary gate. First, the router checks if the requested action exists in the `WRITE_ACTIONS` mapping for the specific tool. If the action is listed as write-only, the router invokes `isWritePermission` to validate the `context.userPermission` value.

When the permission check fails—that is, when a user with `read` permission attempts a write operation—the router throws a permission-denied error. This creates an early exit from the workflow, preventing the tool execution phase from ever being reached.

Conversely, if the action is not found in `WRITE_ACTIONS`, or if the user possesses the required permission level, the workflow proceeds to the tool execution branch where the payload is normalized and the tool is invoked.

## The Conditional Check in routeExecution

Inside the `routeExecution` function (lines 63-73), the branching logic is implemented as a guard clause. Before calling the tool's execution method, the router evaluates the permission context:

```typescript
// Logic flows through these specific lines in router.ts
if (isActionAllowed(toolId, action, context.userPermission)) {
  // Branch A: Permission granted, continue to execution
  return await executeTool(normalizedPayload);
} else {
  // Branch B: Permission denied, throw and abort workflow
  throw new Error(`Permission denied: '${action}' on ${toolId} requires write access.`);
}

```

This implementation ensures that the conditional branch is enforced at the earliest possible point in the request lifecycle, maintaining security boundaries before any business logic executes.

## Practical Code Examples

The following examples demonstrate how the router handles different permission scenarios:

```typescript
// Example: A user with "read" permission attempts to delete a file
await routeExecution('delete_file', { action: 'delete' }, {
  userPermission: 'read',  // Insufficient for write operations
});
// Result: Throws "Permission denied: 'delete' on delete_file requires write access."

// Example: The same user performs a read-only operation
await routeExecution('knowledge_base', { operation: 'search' }, {
  userPermission: 'read',
});
// Result: Proceeds to execution - 'search' is not in WRITE_ACTIONS, so any permission level is valid

```

## Summary

- The router handler at [`apps/sim/lib/copilot/tools/server/router.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/copilot/tools/server/router.ts) implements conditional branching through permission validation rather than traditional if/else workflow constructs.
- The `WRITE_ACTIONS` registry (lines 55-101) defines which tool operations require elevated permissions, serving as the decision matrix for the branching logic.
- Helper functions `isWritePermission` and `isActionAllowed` encapsulate the validation rules, checking if `context.userPermission` meets the requirements for the requested action.
- The `routeExecution` function enforces the branch at lines 63-73, either proceeding to tool execution or throwing a permission-denied error based on the evaluation result.
- This architecture ensures that write-protected tools cannot be invoked by unauthorized users, creating a secure conditional execution path.

## Frequently Asked Questions

### What happens when a user lacks write permissions for a write action?

The router throws a permission-denied error immediately within the `routeExecution` function, preventing the workflow from reaching the tool execution phase. This early termination ensures that no partial state changes occur before the security check completes.

### How does the router distinguish between read and write operations?

The router references the `WRITE_ACTIONS` mapping defined in lines 55-101 of [`router.ts`](https://github.com/simstudioai/sim/blob/main/router.ts), which explicitly lists which actions for each tool require write privileges. Any action not present in this mapping is treated as read-only and permitted regardless of the user's permission level.

### Where is the tool registry defined and how does it relate to branching?

The `serverToolRegistry` contains the available tool definitions, while the conditional branching logic relies on the separate `WRITE_ACTIONS` configuration. The tool catalog in [`apps/sim/lib/copilot/generated/tool-catalog-v1.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/copilot/generated/tool-catalog-v1.ts) provides the tool IDs referenced by both systems, ensuring consistency between available tools and permission requirements.

### Can the permission logic be extended for custom workflow branches?

Yes, the `ServerToolContext` interface defined in [`apps/sim/lib/copilot/tools/server/base-tool.ts`](https://github.com/simstudioai/sim/blob/main/apps/sim/lib/copilot/tools/server/base-tool.ts) carries the `userPermission` field, which can be extended to include additional context flags. Developers could modify `isActionAllowed` (lines 107-118) to evaluate custom conditions such as feature flags, rate limits, or organizational roles beyond the standard read/write/admin hierarchy.