# Sessions vs Direct Execution (/docs/sessions-vs-direct-execution)

> **Legacy.** This is a point-in-time migration/legacy guide and may describe outdated APIs. For current guidance, see https://docs.composio.dev.

A **session** is the runtime context Composio creates for one of your users with `composio.create(userId)`. It ties together the user, available toolkits, auth, and connected accounts. By default it gives your agent [meta tools](/docs/how-composio-works#meta-tools) so the agent discovers which app tools to use, authenticates users, and executes tools at runtime.

**Direct execution** skips the session. Your code fetches specific tool schemas, manages auth itself, and calls `tools.execute()` directly.

Use sessions unless you need full control over which tools are available and when they run.

|                                     | Sessions                                                                                                                                                                    | Direct execution                                                                      |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **Discovery**                       | Agent finds tools at runtime and resolves dependencies automatically (e.g., if a tool needs an ID from another API, the agent finds that tool, runs it, and continues)      | You select all tools upfront and need to account for any dependencies between them    |
| **Context cost**                    | Only meta tools in context, app tools loaded on demand                                                                                                                      | Every tool schema you select is loaded upfront                                        |
| **Guidance**                        | Search returns recommended steps and common pitfalls alongside schemas                                                                                                      | You get tool schemas only                                                             |
| **Memory**                          | Meta tools share context across calls, storing discovered IDs and relationships                                                                                             | You manage state between calls                                                        |
| **Auth**                            | [In-chat](/docs/authentication#in-chat-authentication): agent prompts the user to connect when needed. Also supports [manual](/docs/authentication/manually-authenticating) | You build the auth flow with [connect links](/docs/tools-direct/authenticating-tools) |
| **[Sandbox](/docs/sandbox/remote)** | Built in, large responses offloaded automatically                                                                                                                           | Not available                                                                         |
| **Human approval**                  | You configure approval rules on the session. Harder to intercept individual calls since tools are discovered dynamically                                                    | You intercept before each call in your code                                           |
| **Latency**                         | Multiple LLM turns (search, then execute)                                                                                                                                   | Single call                                                                           |

Sessions are configurable. [Restrict toolkits](/docs/configuring-sessions), set [auth configs](/docs/auth-configuration/custom-auth-configs) for white-labeled OAuth, and pin [connected accounts](/docs/configuring-sessions#account-selection). See [Configuring Sessions](/docs/configuring-sessions) for the full list.

Sessions aren't all-or-nothing. With the [direct tools preset](/docs/configuring-sessions#direct-tools-preset), a session returns a fixed set of tools directly from `session.tools()` with no search or meta tools, so the agent sees exactly the tools you list while you keep session auth, connected accounts, and the sandbox. It's the middle ground between runtime discovery and direct execution.

## Sessions [#sessions]

`composio.create()` returns [meta tools](/docs/how-composio-works#meta-tools):

**Python:**

```python
from composio import Composio
from composio_openai import OpenAIProvider

composio = Composio(provider=OpenAIProvider())
session = composio.create(user_id="user_123")
tools = session.tools()
# Returns meta tools like COMPOSIO_SEARCH_TOOLS, COMPOSIO_MANAGE_CONNECTIONS,
# COMPOSIO_MULTI_EXECUTE_TOOL, COMPOSIO_REMOTE_WORKBENCH, etc.
```

**TypeScript:**

```typescript
import { Composio } from '@composio/core';
import { OpenAIProvider } from '@composio/openai';

const composio = new Composio({
  apiKey: process.env.COMPOSIO_API_KEY,
  provider: new OpenAIProvider(),
});
const session = await composio.create("user_123");
const tools = await session.tools();
// Returns meta tools like COMPOSIO_SEARCH_TOOLS, COMPOSIO_MANAGE_CONNECTIONS,
// COMPOSIO_MULTI_EXECUTE_TOOL, COMPOSIO_REMOTE_WORKBENCH, etc.
```

The agent discovers app tools through `COMPOSIO_SEARCH_TOOLS`:

```
User: "Create a GitHub issue for the login bug"

> Agent calls COMPOSIO_SEARCH_TOOLS({ query: "create github issue" })
  Returns: GITHUB_CREATE_ISSUE schema + connection status

> Agent calls COMPOSIO_MANAGE_CONNECTIONS({ toolkits: ["github"] })
  Returns: confirms connected (or auth link if not)

> Agent calls COMPOSIO_MULTI_EXECUTE_TOOL({ tool: "GITHUB_CREATE_ISSUE", args: {...} })
  Returns: issue details

Agent: "Created issue #42 on your-org/your-repo"
```

> `session.tools()` returns **meta tools** (`COMPOSIO_SEARCH_TOOLS`, etc.), not app tools (`GMAIL_SEND_EMAIL`, etc.). The agent discovers app tools at runtime through search. To work with app tools directly, use direct execution.

### Configuration [#configuration]

Restrict toolkits, set auth configs, pin connected accounts:

**Python:**

```python
session = composio.create(
    user_id="user_123",
    toolkits=["github", "gmail"],
    auth_configs={"github": "ac_my_config"},
    connected_accounts={"gmail": ["ca_work"]},
)
```

**TypeScript:**

```typescript
import { Composio } from '@composio/core';
const composio = new Composio({ apiKey: 'your_api_key' });
const session = await composio.create("user_123", {
  toolkits: ["github", "gmail"],
  authConfigs: { github: "ac_my_config" },
  connectedAccounts: { gmail: ["ca_work"] },
});
```

See [Configuring Sessions](/docs/configuring-sessions) for details.

## Direct execution [#direct-execution]

Fetch tools by slug or toolkit. Pass them to your LLM or call `tools.execute()` without one.

**Python:**

```python
from composio import Composio
from composio_openai import OpenAIProvider

composio = Composio(
    provider=OpenAIProvider(),
    toolkit_versions={"github": "latest"},  # required for direct execution
)

# Fetch specific tools
tools = composio.tools.get(
    user_id="user_123",
    tools=["GITHUB_CREATE_ISSUE", "GITHUB_LIST_ISSUES"]
)

# Or by toolkit
tools = composio.tools.get(
    user_id="user_123",
    toolkits=["github"],
    limit=50
)

# Execute without an LLM
result = composio.tools.execute(
    "GITHUB_CREATE_ISSUE",
    user_id="user_123",
    arguments={"owner": "my-org", "repo": "my-repo", "title": "Fix login bug"},
    dangerously_skip_version_check=True,  # required when running "latest"; or pin via version=...
)
```

**TypeScript:**

```typescript
import { Composio } from '@composio/core';
import { OpenAIProvider } from '@composio/openai';

const composio = new Composio({
  apiKey: process.env.COMPOSIO_API_KEY,
  provider: new OpenAIProvider(),
  toolkitVersions: { github: 'latest' },  // required for direct execution
});

// Fetch specific tools
const tools = await composio.tools.get("user_123", {
  tools: ["GITHUB_CREATE_ISSUE", "GITHUB_LIST_ISSUES"],
});

// Or by toolkit
const allTools = await composio.tools.get("user_123", {
  toolkits: ["github"],
  limit: 50,
});

// Execute without an LLM
const result = await composio.tools.execute("GITHUB_CREATE_ISSUE", {
  userId: "user_123",
  arguments: { owner: "my-org", repo: "my-repo", title: "Fix login bug" },
  dangerouslySkipVersionCheck: true, // required when running "latest"; or pin via version
});
```

> `tools.get()` returns 20 tools by default. When fetching from multiple toolkits (e.g., `toolkits=["gmail", "github", "tavily"]`), the limit may cut off tools from later toolkits. Increase `limit` or fetch each toolkit separately.

With direct execution, you manage [auth configs](/docs/auth-configuration/custom-auth-configs), [connect links](/docs/tools-direct/authenticating-tools), and [toolkit versioning](/docs/tools-direct/toolkit-versioning) yourself.

## Migrating [#migrating]

See the [migration guide](/docs/migration-guide/direct-to-sessions). Auth configs and connected accounts carry over.

## Next [#next]

- [Configuring Sessions](/docs/configuring-sessions): Toolkits, auth configs, and connected accounts

---

📚 **More documentation:** [View all docs](https://docs.composio.dev/llms.txt) | [Glossary](https://docs.composio.dev/llms.mdx/reference/glossary) | [Examples](https://docs.composio.dev/llms.mdx/examples) | [API Reference](https://docs.composio.dev/llms.mdx/reference)