# Background Agent (/cookbooks/background-agent)

[View source on GitHub](https://github.com/ComposioHQ/composio/tree/next/docs/examples/background-agent)

This cookbook builds a background agent that runs a "morning sweep" across your apps. It checks GitHub for PRs that need your review, finds unanswered emails in Gmail, and posts a summary to Slack. One script, three apps, zero human input.

Run it manually, put it on a cron, or deploy it. The agent does the rest.

# Prerequisites

* Node.js 18+
* [Composio API key](https://platform.composio.dev/settings)
* [OpenAI API key](https://platform.openai.com/api-keys)

# Project setup

Create a new project and install dependencies:

```bash
mkdir composio-background-agent && cd composio-background-agent
npm init -y
npm install ai @ai-sdk/openai @composio/core @composio/vercel dotenv tsx
```

Add your API keys to a `.env` file:

```bash title=".env"
COMPOSIO_API_KEY=your_composio_api_key
OPENAI_API_KEY=your_openai_api_key
```
# Initializing the clients

`Composio` takes a `VercelProvider` so that tools come back as Vercel AI SDK tools with built-in execution. No manual tool-call loop needed.

```ts no-twoslash
const composio = new Composio({ provider: new VercelProvider() });
const userId = process.env.COMPOSIO_USER_ID ?? "default";
const model = openai("gpt-5.4");
```
# The sweep

The entire agent is one function. Create a session, get tools, and give the model a prompt describing what to do. `generateText` with `stopWhen: stepCountIs(15)` lets the model call as many tools as it needs, discovering available actions, authenticating with apps, and executing across GitHub, Gmail, and Slack, all in a single run.

```ts no-twoslash
async function sweep() {
  const session = await composio.create(userId);
  const tools = await session.tools();

  const { text } = await generateText({
    model,
    tools,
    stopWhen: stepCountIs(15),
    prompt: `You are an autonomous background agent running a scheduled sweep.

Do the following, in order:

1. **GitHub**:Find pull requests where my review is requested.
   List each PR with its title, repo, and link.

2. **Gmail**:Find emails from the last 24 hours that I haven't replied to.
   List each with sender and subject.

3. **Slack**: Post a concise summary of your findings to the #morning-sweep channel.
   Format it as a digest with sections for PRs and emails.
   If nothing was found, say so.

If an app is not connected, skip it and note it in the summary.
Be concise and actionable.`,
  });

  console.log(text);
}

sweep();
```
That's it. The agent figures out which tools to call, handles pagination, formats the results, and posts to Slack. Composio's meta-tools handle tool discovery and auth inline. If an app isn't connected, the agent skips it gracefully.

# Complete script

```ts no-twoslash title="sweep.ts"
import "dotenv/config";
import { openai } from "@ai-sdk/openai";
import { generateText, stepCountIs } from "ai";
import { Composio } from "@composio/core";
import { VercelProvider } from "@composio/vercel";

// #region setup
const composio = new Composio({ provider: new VercelProvider() });
const userId = process.env.COMPOSIO_USER_ID ?? "default";
const model = openai("gpt-5.4");
// #endregion setup

// #region sweep
async function sweep() {
  const session = await composio.create(userId);
  const tools = await session.tools();

  const { text } = await generateText({
    model,
    tools,
    stopWhen: stepCountIs(15),
    prompt: `You are an autonomous background agent running a scheduled sweep.

Do the following, in order:

1. **GitHub**:Find pull requests where my review is requested.
   List each PR with its title, repo, and link.

2. **Gmail**:Find emails from the last 24 hours that I haven't replied to.
   List each with sender and subject.

3. **Slack**: Post a concise summary of your findings to the #morning-sweep channel.
   Format it as a digest with sections for PRs and emails.
   If nothing was found, say so.

If an app is not connected, skip it and note it in the summary.
Be concise and actionable.`,
  });

  console.log(text);
}

sweep();
// #endregion sweep

```
# Running the sweep

```bash
npx tsx sweep.ts
```
Example output:

```
## GitHub: PRs where your review is requested (3)
- fix: robust platform detection (ComposioHQ/composio)
  https://github.com/ComposioHQ/composio/pull/2712
- docs: add retry to health check workflow (ComposioHQ/composio)
  https://github.com/ComposioHQ/composio/pull/2711
- chore(deps): bump next (ComposioHQ/composio)
  https://github.com/ComposioHQ/composio/pull/2473

## Gmail: Emails from last 24h you haven't replied to (1)
- Stephanie M. - CoreWeave - We'd love to chat!

## Slack: Digest posted to #morning-sweep
```
> If an app isn't connected yet, the agent will return an authentication link in the output. Open it in your browser to complete OAuth, then run the sweep again.

# Running on a schedule

The agent runs once and exits, which makes it perfect for cron jobs. Pick whichever scheduler you prefer.

## crontab (every day at 8am)

```bash
crontab -e
```
```
0 8 * * * cd /path/to/composio-background-agent && npx tsx sweep.ts >> sweep.log 2>&1
```
## GitHub Actions

```yaml title=".github/workflows/sweep.yml"
name: Morning Sweep
on:
  schedule:
    - cron: '0 8 * * *' # 8am UTC daily
  workflow_dispatch: # manual trigger

jobs:
  sweep:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm install
      - run: npx tsx sweep.ts
        env:
          COMPOSIO_API_KEY: ${{ secrets.COMPOSIO_API_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
```

# Take it further

The prompt is the agent's brain. Change it to change what it does. Some ideas:

* **Triage support tickets**: scan Zendesk for unassigned tickets, categorize them, assign to the right team in Linear
* **Daily standup prep**: pull yesterday's commits from GitHub, completed tasks from Linear, and draft a standup summary
* **Invoice follow-up**: check QuickBooks for overdue invoices, draft follow-up emails in Gmail

- [Hono Server](/cookbooks/hono): Wrap this agent in an HTTP server so multiple users can interact with it

- [Vercel AI SDK Provider](/docs/providers/vercel): Learn more about how Composio tools work with the Vercel AI SDK

---

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

---

# Composio SDK — Instructions for AI Code Generators

**Purpose:** Enforce only the **current** and **correct** patterns for integrating [Composio](https://composio.dev/) tools into AI agents.
**Scope:** All AI-generated code using Composio must follow these guardrails.

---

## 1. Correct Composio Integration

Composio supports two integration modes: **Native Tools** (with a provider package) and **MCP** (no provider package needed).

### Native Tools

```python
# ✅ CORRECT — Python (defaults to OpenAI)
from composio import Composio

composio = Composio()
session = composio.create(user_id="user_123")
tools = session.tools()
# Pass tools to your agent/LLM framework
```

```typescript
// ✅ CORRECT — TypeScript (defaults to OpenAI)
import { Composio } from "@composio/core";

const composio = new Composio();
const session = await composio.create("user_123");
const tools = await session.tools();
// Pass tools to your agent/LLM framework
```

For other providers, pass the provider explicitly. Provider packages follow the naming convention: `composio_<provider>` for Python, `@composio/<provider>` for TypeScript.

### MCP

Use `session.mcp.url` and `session.mcp.headers` with any MCP-compatible client (Claude Desktop, Cursor, OpenAI Agents, etc.). No provider package needed.

---

## 2. CRITICAL INSTRUCTIONS FOR AI MODELS

### 2.1 — ALWAYS DO THE FOLLOWING

1. **Use `composio.create(user_id)`** to create a session — this is the entry point for all Composio integrations.
2. **Use `session.tools()`** for native tool integration or **`session.mcp.url`** for MCP integration.
3. **Import** from the correct provider package (`composio_<provider>` for Python, `@composio/<provider>` for TypeScript).
4. **Pass `user_id` to `composio.create()`**, not to individual tool calls.

### 2.2 — NEVER DO THE FOLLOWING

1. **Do not** instruct users to manually create auth configs or connected accounts before running.
2. **Do not** import from `composio_openai` / `@composio/openai` when using OpenAI Agents SDK — use `composio_openai_agents` / `@composio/openai-agents` instead.

### 2.3 — DISCOURAGED (do not use unless user explicitly asks)

Do **not** generate `composio.tools.get()`, `composio.tools.execute()`, or `composio.provider.handle_tool_calls()` unless the user explicitly requests direct tool execution. These are a supported but **not recommended** low-level interface.


---

## Terminology Migration (old → current)

If you encounter these terms in error messages, old documentation, or user prompts, translate them to the current equivalents. **Do not use the old terms in generated code or explanations.**

| Old term (v1/v2) | Current term (v3) | In code |
|---|---|---|
| entity ID | user ID | `user_id` parameter |
| actions | tools | e.g., `GITHUB_CREATE_ISSUE` is a *tool* |
| apps / appType | toolkits | e.g., `github` is a *toolkit* |
| integration / integration ID | auth config / auth config ID | `auth_config_id` parameter |
| connection | connected account | `connected_accounts` namespace |
| ComposioToolSet / OpenAIToolSet | `Composio` class with a provider | `Composio(provider=...)` |
| toolset | provider | e.g., `OpenAIProvider` |

If a user says "entity ID", they mean `user_id`. If they say "integration", they mean "auth config". Always respond using the current terminology.

