Triage a Gmail inbox with AgentKit and the LiteLLM gateway
Node.js inbox triage agent: classify Gmail threads, route to GitHub repos, draft issues and replies via LiteLLM, and approve before any side effects.
Build an automated inbox triage agent that reads your Gmail, classifies each thread, routes it to the right GitHub repository, and notifies Slack — then waits for your approval before creating issues or sending replies. This Node.js sample uses Scalekit AgentKit for OAuth tool execution (Gmail, GitHub, Slack) and a LiteLLM gateway for model-per-stage routing. The only LiteLLM-specific config is LITELLM_BASE_URL and a virtual API key from the dashboard.
The sample repository is litellm-agentkit-inbox-triage on GitHub.
What you are building
Section titled “What you are building”- Gmail ingestion — Poll for new threads using AgentKit-executed Gmail tools. A SQLite cursor prevents duplicate processing.
- Model-per-stage routing — Each stage (
classify,research,tiebreak,draft) calls the LiteLLM gateway with a different model name. Stage-to-model assignments live inrouting.yamlat the repo root. - Deterministic GitHub routing — Keyword rules in
routing.yamlpick a target repository; an optional LLM tie-breaker resolves ties. - Research loop — A small tool-calling loop searches related GitHub issues through AgentKit.
- Slack notification — Posts a summary with a link to the pending decision.
- Human approval — A localhost dashboard lists proposals. Approve creates the GitHub issue, sends the Gmail reply, and updates Slack. Reject discards without side effects.
Automated triage pipeline
Section titled “Automated triage pipeline”New Gmail threads flow through AgentKit into a multi-stage LiteLLM pipeline, then land in SQLite as pending proposals.
Human approval loop
Section titled “Human approval loop”Proposals wait in SQLite until you review them from the dashboard.
Prerequisites
Section titled “Prerequisites”- A Scalekit account at app.scalekit.com.
- Ability to create AgentKit connections for Gmail, GitHub, and Slack. Connection names must match what you put in
.env(see Configure a connection). - A virtual LiteLLM API key from the dashboard (LLM Gateway). A small spend cap of roughly two US dollars covers a handful of test threads.
- Node.js 24 or newer and npm.
- An interactive terminal — the sample prints authorization links and waits for Enter after each connector. This recipe does not cover headless CI.
-
Clone the sample
Section titled “Clone the sample”Terminal window git clone https://github.com/scalekit-developers/litellm-agentkit-inbox-triage.gitcd litellm-agentkit-inbox-triage -
Configure AgentKit connections
Section titled “Configure AgentKit connections”- Open app.scalekit.com → AgentKit → Connections → Create Connection for Gmail, GitHub, and Slack.
- Copy each Connection name exactly as shown in the dashboard into
GMAIL_CONNECTION_NAME,GITHUB_CONNECTION_NAME, andSLACK_CONNECTION_NAMEin your.envfile. - For GitHub, confirm the connection includes the
repoOAuth scope (needed to create issues and search across repositories). Check AgentKit → Connections → GitHub → Scopes in the dashboard. See Scopes and permissions and the GitHub connector. - For Gmail and Slack, follow the dashboard wizard. If your workspace restricts OAuth apps, see the connector docs: Gmail, Slack.
-
Create a LiteLLM virtual key and verify the gateway
Section titled “Create a LiteLLM virtual key and verify the gateway”Open LLM Gateway in the Scalekit dashboard and create a virtual API key (optionally set a small budget cap for evaluation).
Verify the gateway responds before continuing (load your
.envfirst withset -a && source .env && set +a):Terminal window curl -H "Authorization: Bearer $LITELLM_API_KEY" \"$LITELLM_BASE_URL/v1/models"Align
routing.yaml→models:with the model IDs returned by that endpoint. -
Configure and run the sample
Section titled “Configure and run the sample”Set these variables in
.envbefore running:Variable Where to find it SCALEKIT_ENV_URLDashboard → Settings → Environment URL SCALEKIT_CLIENT_IDDashboard → API Credentials SCALEKIT_CLIENT_SECRETDashboard → API Credentials GMAIL_CONNECTION_NAMEDashboard → AgentKit → Connections (exact label) GITHUB_CONNECTION_NAMESame SLACK_CONNECTION_NAMESame LITELLM_BASE_URLDashboard → LLM Gateway → Base URL LITELLM_API_KEYDashboard → LLM Gateway → virtual key value Terminal window cp .env.example .env# Fill in the variables abovenpm installnpm run devComplete each printed authorization URL in the browser, then press Enter in the terminal after each connector.
When you see All connectors active and dashboard listening on
http://localhost:3000, send a test email to the connected Gmail account. Within roughly one poll interval (default 5 seconds), a proposal appears in the dashboard. -
Approve or reject
Section titled “Approve or reject”Open
http://localhost:3000. Review the classification, routed repository, related issues, and drafts. Approve runs GitHub issue creation, sends the Gmail reply, and updates Slack. Reject leaves external systems unchanged. -
Extend the sample
Section titled “Extend the sample”To add routing targets or swap models per stage, edit
routing.yaml— each entry maps keyword rules to a GitHub repository and assigns a model name to each pipeline stage. To add connectors, follow the AgentKit connections guide and add the new connection name to.env.
Related resources
Section titled “Related resources”| Topic | Link |
|---|---|
| AgentKit overview | Overview |
| Connections | Configure a connection |
| Authorization links | Authorize a user |
| Connected accounts | Manage connected accounts |
| LiteLLM virtual keys | Virtual keys |
| LiteLLM model routing | Router |
| LiteLLM OpenAI-compatible API | Proxy usage |
Common scenarios
Section titled “Common scenarios”Why am I seeing random tool failures or connection not found errors?
The *_CONNECTION_NAME variables in .env must match the connection labels exactly as shown in the dashboard — including capitalization and spacing.
Solution: Open AgentKit → Connections in the dashboard, copy each connection name exactly, and paste it into GMAIL_CONNECTION_NAME, GITHUB_CONNECTION_NAME, and SLACK_CONNECTION_NAME.
Why is GitHub returning a 403 or permission error?
The GitHub AgentKit connection is missing the repo OAuth scope, which is required to create issues and search across repositories.
Solution: In the dashboard, go to AgentKit → Connections → GitHub → Scopes and confirm repo is included. Re-authorize the connection if you need to add it.
Why am I seeing unknown model errors from LiteLLM?
A model name in routing.yaml is not available on your LiteLLM gateway instance.
Solution: Run the following to list available models, then update routing.yaml → models: to match:
curl -H "Authorization: Bearer $LITELLM_API_KEY" \ "$LITELLM_BASE_URL/v1/models"Why isn’t the dashboard loading at localhost:3000?
The sample binds the dashboard only after all three connectors finish authorization. If any connector step was skipped or the terminal is still waiting for Enter, the dashboard won’t start.
Solution: Check the terminal output — the sample prints an authorization URL for each connector and waits for you to press Enter after completing it in the browser.
For deeper debugging patterns, see Authentication troubleshooting.