> **Building with AI coding agents?** If you're using an AI coding agent, install the official Scalekit plugin. It gives your agent full awareness of the Scalekit API — reducing hallucinations and enabling faster, more accurate code generation.
>
> - **Claude Code**: `/plugin marketplace add scalekit-inc/claude-code-authstack` then `/plugin install <auth-type>@scalekit-auth-stack`
> - **GitHub Copilot CLI**: `copilot plugin marketplace add scalekit-inc/github-copilot-authstack` then `copilot plugin install <auth-type>@scalekit-auth-stack`
> - **Codex**: run the bash installer, restart, then open Plugin Directory and enable `<auth-type>`
> - **Skills CLI** (Windsurf, Cline, 40+ agents): `npx skills add scalekit-inc/skills --list` then `--skill <skill-name>`
>
> `<auth-type>` / `<skill-name>`: `agentkit`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim` — [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# 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](https://github.com/scalekit-developers/litellm-agentkit-inbox-triage)** on GitHub.

## 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 in `routing.yaml` at the repo root.
- **Deterministic GitHub routing** — Keyword rules in `routing.yaml` pick 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

New Gmail threads flow through AgentKit into a multi-stage LiteLLM pipeline, then land in SQLite as pending proposals.

```d2 pad=28 layout=dagre
direction: right

gmail: "Gmail inbox" {
  style.font-size: 16
}
ingest: "Ingest\n(AgentKit)" {
  style.font-size: 16
}

litellm: "LiteLLM pipeline" {
  direction: right
  style.font-size: 16
  classify: "Classify" {
    style.font-size: 16
  }
  route: "Route\n(routing.yaml)" {
    style.font-size: 16
  }
  research: "Research\n(AgentKit)" {
    style.font-size: 16
  }
  draft: "Draft" {
    style.font-size: 16
  }

  classify -> route
  route -> research
  research -> draft
}

sqlite: "Store\n(SQLite)" {
  style.font-size: 16
}

gmail -> ingest
ingest -> litellm.classify
litellm.draft -> sqlite
```

## Human approval loop

Proposals wait in SQLite until you review them from the dashboard.

```d2 pad=28 layout=dagre
direction: right

sqlite: "Pending proposal\n(SQLite)" {
  style.font-size: 16
}
notify: "Notify Slack\n(AgentKit)" {
  style.font-size: 16
}
ui: "Dashboard\n(localhost:3000)" {
  style.font-size: 16
}
approve: "Approve" {
  style.font-size: 16
}
reject: "Reject\n(no side effects)" {
  style.font-size: 16
}
act: "Create issue\n+ send reply\n(AgentKit)" {
  style.font-size: 16
}

sqlite -> notify
notify -> ui
ui -> approve: approve
ui -> reject: reject
approve -> act
```

## Prerequisites

- A Scalekit account at [app.scalekit.com](https://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](/agentkit/connections/)).
- 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.

1. ## Clone the sample

   ```bash
   git clone https://github.com/scalekit-developers/litellm-agentkit-inbox-triage.git
   cd litellm-agentkit-inbox-triage
   ```

2. ## Configure AgentKit connections

   1. Open [app.scalekit.com](https://app.scalekit.com) → **AgentKit** → **Connections** → **Create Connection** for **Gmail**, **GitHub**, and **Slack**.
   2. Copy each **Connection name** exactly as shown in the dashboard into `GMAIL_CONNECTION_NAME`, `GITHUB_CONNECTION_NAME`, and `SLACK_CONNECTION_NAME` in your `.env` file.
   3. For **GitHub**, confirm the connection includes the **`repo`** OAuth scope (needed to create issues and search across repositories). Check **AgentKit → Connections → GitHub → Scopes** in the dashboard. See [Scopes and permissions](/agentkit/authentication/scopes-permissions/) and the [GitHub connector](/agentkit/connectors/github/).
   4. For **Gmail** and **Slack**, follow the dashboard wizard. If your workspace restricts OAuth apps, see the connector docs: [Gmail](/agentkit/connectors/gmail/), [Slack](/agentkit/connectors/slack/).

   > caution: Dashboard only loads after all three connectors are active
>
> The sample calls `setupConnectors` **before** it binds the Express dashboard. You will **not** reach `http://localhost:3000` until Gmail, GitHub, and Slack each show **connector active** in the logs.

3. ## 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 `.env` first with `set -a && source .env && set +a`):

   ```bash
   curl -H "Authorization: Bearer $LITELLM_API_KEY" \
        "$LITELLM_BASE_URL/v1/models"
   ```

   Align `routing.yaml` → `models:` with the model IDs returned by that endpoint.

4. ## Configure and run the sample

   Set these variables in `.env` before running:

   | Variable | Where to find it |
   |---|---|
   | `SCALEKIT_ENV_URL` | Dashboard → **Settings** → Environment URL |
   | `SCALEKIT_CLIENT_ID` | Dashboard → **API Credentials** |
   | `SCALEKIT_CLIENT_SECRET` | Dashboard → **API Credentials** |
   | `GMAIL_CONNECTION_NAME` | Dashboard → **AgentKit → Connections** (exact label) |
   | `GITHUB_CONNECTION_NAME` | Same |
   | `SLACK_CONNECTION_NAME` | Same |
   | `LITELLM_BASE_URL` | Dashboard → **LLM Gateway** → Base URL |
   | `LITELLM_API_KEY` | Dashboard → **LLM Gateway** → virtual key value |

   ```bash
   cp .env.example .env
   # Fill in the variables above

   npm install
   npm run dev
   ```

   Complete 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.

5. ## 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.

6. ## 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](/agentkit/connections/) and add the new connection name to `.env`.

## Related resources

| Topic | Link |
|---|---|
| AgentKit overview | [Overview](/agentkit/overview/) |
| Connections | [Configure a connection](/agentkit/connections/) |
| Authorization links | [Authorize a user](/agentkit/tools/authorize/) |
| Connected accounts | [Manage connected accounts](/agentkit/connected-accounts/) |
| LiteLLM virtual keys | [Virtual keys](https://docs.litellm.ai/docs/proxy/virtual_keys) |
| LiteLLM model routing | [Router](https://docs.litellm.ai/docs/routing) |
| LiteLLM OpenAI-compatible API | [Proxy usage](https://docs.litellm.ai/docs/proxy/user_keys) |

## Common scenarios

## Why am I seeing random tool failures or <code>connection not found</code> 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 <code>403</code> 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 <code>unknown model</code> 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:

```bash
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](/agentkit/authentication/troubleshooting/).


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
