docs/content/cookbooks/workplace-search.mdx
Build a search agent that queries across your workplace tools and returns answers with citations. One session, four toolkits.
session.authorize() and wait_for_connection()mkdir composio-workplace-search && cd composio-workplace-search
uv init && uv add composio composio-openai-agents openai-agents
COMPOSIO_API_KEY=your_composio_api_key
OPENAI_API_KEY=your_openai_api_key
USER_ID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
composio-workplace-search/
authorize.py # One-time: connect GitHub, Slack, Gmail, Notion
agent.py # The search agent
.env
Before the agent can search, each toolkit needs an active connection. authorize.py walks through them one by one, skipping any that are already connected.
<include>../../examples/workplace-search/authorize.py</include>
Run it once:
uv run --env-file .env python authorize.py
Each toolkit prints a URL. Open it in a browser, complete OAuth, and the script moves to the next one. You only need to do this once per user.
<Callout> If you're using sessions with meta tools (`COMPOSIO_MANAGE_CONNECTIONS`), authentication happens in-chat automatically. This manual flow is useful when you want to pre-connect apps once locally before deploying `agent.py` to a CI pipeline or scheduled job. </Callout><include>../../examples/workplace-search/agent.py#setup</include>
The prompt tells the agent to search across apps, synthesize findings, and cite every source. If a toolkit isn't connected, it skips it instead of failing.
<include>../../examples/workplace-search/agent.py#agent</include>
session.tools() returns provider-wrapped tools ready for the OpenAI Agents SDK. The USER_ID from your .env file scopes all connections to that user.
<include>../../examples/workplace-search/agent.py#search</include>
uv run --env-file .env python agent.py "What decisions were made about the v2 migration?"
Or start it interactively:
uv run --env-file .env python agent.py
Example output:
Based on my search across your connected apps:
**GitHub**: PR #412 "v2 migration plan" (merged Feb 15) outlines the database
schema changes. Issue #389 tracks the remaining blockers.
(Source: github.com/acme/backend/pull/412)
**Slack**: In #engineering on Feb 14, @alice proposed splitting the migration
into two phases. The team agreed in the thread.
(Source: #engineering, Feb 14)
**Gmail**: No relevant emails found for "v2 migration".
**Notion**: Skipped (not connected)
authorize.py connects each toolkit via OAuth using session.authorize() and wait_for_connection(). It checks session.toolkits() first to skip already-connected apps.USER_ID in .env scopes all connections — swap it to switch users without changing code.The prompt and toolkits are the only moving parts. Change them to change what the agent searches: