README.md
Rama main · réplica de lectura del repositorio original.
<p align="center">
<img src="assets/chickpea-mark.png" alt="" width="96" height="96">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/chickpea-wordmark-512-dark.png">
<img src="assets/chickpea-wordmark-512.png" alt="Chickpea" height="56">
</picture>
</p>
<p align="center">
<strong>AI teammates in Slack that answer questions, take on tasks, and use the accounts you give them, all on infrastructure you own.</strong>
</p>
<div align="center">
[](./LICENSE)
[](https://nodejs.org)
[](#deploy-it-yourself)
[](https://flueframework.com)
<br />
<img src="assets/admin-agent.png" alt="Chickpea Admin, showing the Sprout Agent: its Slack destination, and the Google Docs, Drive, Sheets, Gmail, and Calendar accounts it can use" width="880">
<br /><br />
<a href="#install-on-cloudflare"><img src="assets/install-cloudflare.svg" alt="Install on Cloudflare" height="46"></a> <a href="#install-on-your-mac"><img src="assets/install-mac.svg" alt="Install on your Mac" height="46"></a>
<sub>Paste one prompt into Claude Code, Codex, or Cursor. Chickpea runs in your own Cloudflare account or on your own Mac.</sub>
Already installed? [Connect via MCP](#connect-via-mcp) · [Update](#update-chickpea)
[Website](https://chickpea.co) · [Docs](https://docs.chickpea.co)
<br />
[Why it exists](#why-chickpea-exists) · [Features](#what-your-workspace-gets) · [How it works](#how-it-works) · [Managing](#managing-chickpea) · [CLI](#cli) · [Security](#security-model) · [Deployment](#deploy-it-yourself) · [Good to know](#good-to-know) · [FAQ](#faq)
</div>
Chickpea gives your team AI teammates in Slack. You address them by name. `@support` answers the billing question in the channel where someone asked it. `@revops` posts Monday's pipeline numbers from HubSpot on a schedule. `@oncall` reads the repo before it answers. Each one has its own instructions, memory, connected accounts, and list of channels it's allowed to work in. You set all of that up by asking, in Slack.
The difference is where they work. Chickpea is licensed under Apache 2.0 and you deploy it yourself, to your own Cloudflare account or your own server, pointed at whichever model provider you want. Under the hood every Agent runs on [Flue](https://flueframework.com), the open agent framework from the Astro team, now part of Cloudflare. More in [How It Works](#how-it-works).
---
## Why Chickpea Exists
Your team already uses AI all day, one person at a time in a private tab, and the answer stays in that one person's history. Ask in the channel instead:
> **`@growth`** which pages lost impressions in Search Console last month?
`@growth` checks Search Console, cross-references Google Analytics, and answers in the thread. `@sales` pulls the recurring objections out of this week's Gong calls. `@eng` names the top new Sentry issue since Friday's deploy. Ask any of them to update a HubSpot record or move something on your Google Calendar, and they make the change, as long as the connection allows writes. Everyone in the channel sees the answer, and anyone can pick it up later without starting over.
The hosted versions of this idea run on the vendor's infrastructure, with the vendor's model, on the vendor's schedule. Good products, and for a lot of teams that trade is fine. Some teams can't make it, for reasons of policy or data, and they have mostly gone without.
Chickpea is for those teams. Each Agent keeps its own connected accounts and its own channels, so the support Agent can't read finance's inbox; nobody ever gave it to them. If you need a wall between two jobs, make a second Agent.
---
## What Your Workspace Gets
| Feature | What it does | |
|---|---|---|
| **Addressable Agents** | Each Agent gets a real Slack handle (a zero-member user group like `@support`), a distinct generated avatar, and its own name on every reply. | |
| **Agent memory** | One memory per Agent, shared across its DMs and every granted channel, editable and deletable in Admin. | [Details](#memory) |
| **Connection accounts** | Team accounts and personal accounts, each owned by one Agent. 105 connector presets, plus native API and MCP for anything custom. | [Details](#connections-and-authority) |
| **Model choice** | Anthropic, OpenAI, Google Gemini, OpenRouter, or Cloudflare Workers AI, pinned per Agent. | [Details](#models-and-providers) |
| **Skills** | Import from a GitHub repo or a `skills.sh` link, in Admin or by handing the link to an Agent in Slack. You see which skills were found before anything is installed. | |
| **Repositories** | Grant GitHub repositories to an Agent through the Chickpea GitHub App (Settings → GitHub). Access uses short-lived installation tokens scoped to the granted repositories. | |
| **Coding sandbox** | Optional Cloudflare container tier for Agents that need to clone a repo, install packages, and run tests. | [Details](#coding-sandbox) |
| **Browser** | Optional. Agents open a real browser in your own Browserbase project to check live pages, sign in with website logins you grant, and attach a screenshot or recording as proof. Connect it in Settings → Browser. | |
| **Schedules** | Agent-owned recurring or one-time work, set up conversationally in Slack, delivered to a granted channel or a private DM thread. | [Details](#schedules) |
| **Manage from Slack** | Admin, Slack, and an MCP server are three doors to the same controls. Create Agents, install skills, set schedules, and edit memory by asking, with consequential changes gated behind an approval. Connect your coding agent from Settings → MCP or with one pasted line. | [Details](#managing-chickpea) |
| **Slack-native answers** | Progressive streaming for long replies, adaptive tables (prose, inline Markdown, or a native sortable Slack table) when the data earns one, and progress in Slack's working indicator while long work runs. | |
| **Reads Slack** | Agents see who said what in a thread, including alert and bot posts, and can read a linked thread, another channel they are added to, or a person's profile, within the requester's own channel access. Nothing is kept beyond the threads an Agent is part of. | [Details](docs/runbooks/slack-reading.md) |
| **Reads attachments** | Images, PDFs, UTF-8 text and source files, Slack's generated previews for docs, slides, and sheets, and zip archives, listed on arrival and read file by file on request. Earlier files in the conversation stay readable in follow-up messages. A file is untrusted reference material: its contents inform the answer, and text inside it never authorizes a tool or a change. | [Details](docs/runbooks/slack-reading.md#files) |
| **Files** | Agents attach final or revised sandbox deliverables, including Markdown, through their Slack reply. Scratch files stay private, and explicit no-attachment requests are respected. Missed exports get one repair attempt; files that cannot be attached are identified in the reply. Files upload straight to Slack on both direct and shared-app installs, up to Slack's 1 GB limit; browser recordings stream, and the shared gateway only issues the upload ticket. Works without a coding sandbox or repository grant on Cloudflare and Node. | |
| **Live activity status** | Slack's native under-composer status shows real phases as they happen: `Checking Gmail…`, `Drafting the response…`. | |
---
## How It Works
### In Slack
Someone in `#billing` types:
> **`@support`** can we refund order 4821? The customer says the card was charged twice.
1. **Slack renders the mention.** `@support` is a Slack user group with zero members, created when the Agent was. To Slack it is an ordinary handle. To Chickpea it is an address.
2. **Chickpea checks the grant.** One deployment holds every Agent, and a channel grant says which Agent may work in which channel. If `@support` has no grant for `#billing`, nothing happens. Mention several Agents in one message and each answers in turn, in the order you named them; the first one keeps the thread.
3. **The Agent runs as itself.** Its own instructions, its own memory, its own skills, and its own connected accounts, say Zendesk and Stripe. Nothing that belongs to `@revops` is in the room.
4. **The reply lands in the thread under `@support`'s name and avatar,** streamed as it's written. The thread now belongs to `@support`. Anyone in the channel can follow up there without mentioning it again, and mentioning `@finance` in the same thread hands the work over in the open.
5. **Agents ask each other, in the open.** If `@support` needs something only `@finance` knows, its reply mentions `@finance` and Finance answers in the same thread, without taking it over. A person's message can lead to at most eight such asks before the Agents pause for a person. See [Agent conversations](docs/runbooks/agent-conversations.md).
Want another teammate? Ask `@Chickpea` for one, in Slack or in Admin. [Managing Chickpea](#managing-chickpea) covers what else you can do from each.
Drawn out, a workspace looks like this. Solid lines are channel grants, dotted lines are connected accounts.
```mermaid
flowchart LR
zs["Zendesk · Stripe"] -.- support["@support"]
gh["GitHub · Sentry"] -.- oncall["@oncall"]
hs["HubSpot · Google Sheets"] -.- revops["@revops"]
subgraph cp["Chickpea, one deployment"]
support
oncall
revops
end
subgraph slack["Slack workspace"]
billing["#billing"]
eng["#eng"]
fin["#finance (private)"]
end
support --- billing
oncall --- billing
oncall --- eng
revops --- fin
```
`@oncall` can answer in `#billing` but has no Zendesk. `@support` has Zendesk but cannot see `#eng`. Publishing an Agent to a channel hands that channel's members everything the Agent can do and reach, so think about that before you publish.
Publishing to a public channel joins the bot automatically. Private channels need someone to `/invite @Chickpea` first, and the grant stays pending until then. Where an Agent is published also decides who can DM it. In a public channel, any workspace member can. Only in private channels, only those members can. Unpublished, only its creator can.
In every channel, a top-level message that mentions no one is dropped before any model is involved. Chickpea is not sitting in your channels forming opinions.
<details>
<summary><strong>If Slack blocks user-group creation</strong></summary>
Agent handles are Slack user groups, which some plans restrict. If Slack blocks the group, Chickpea keeps the Agent and shows the fix:
1. A Workspace Owner or Admin opens **Roles & permissions → Account types** at `slack.com/admin`.
2. Next to **Create and edit user groups**, choose **Edit permission**.
3. Add Members and save.
4. Return to the Agent and choose **Retry**.
On Enterprise Grid it's the equivalent setting under **Organization settings → Roles & permissions**. Reconnecting Slack cannot repair a policy, so Chickpea won't suggest it.
</details>
### Under the hood
| Layer | What it does |
|---|---|
| **Slack app** | Events API, DMs, App Home, message delivery. Transport only. |
| **Chickpea** | Routes mentions to Agents, enforces channel grants and confirmation policy, resolves credentials at the moment of each call, renders replies as the Agent, and runs Admin and the management MCP. |
| **[Flue](https://flueframework.com)** | The agent runtime: durable sessions that survive crashes and restarts, persistent state, subagents, tools, skills, and MCP. Same code on Cloudflare Workers or Node. |
| **Pi** | The open agent harness Flue runs on, also behind OpenClaw. |
| **Model provider** | Anthropic, OpenAI, Google Gemini, OpenRouter, or Cloudflare Workers AI, pinned per Agent. |
| **State** | Durable Objects and D1 on Cloudflare. SQLite files on Node. |
Chickpea has no agent loop of its own. That is Flue ([`@flue/runtime`](https://www.npmjs.com/package/@flue/runtime)), the Apache-licensed open agent framework from the [Astro](https://astro.build) team, now part of Cloudflare. Everything above the Flue row in the table is Chickpea's: the Slack product, the authority model, and the admin panel.
---
## Connections and Authority
Every connection belongs to one Agent for its lifetime. A **team account** is shared authority the Agent's editors manage, like the support team's Zendesk. A **personal account** belongs to one member inside one Agent, like your work Gmail, and runtime use requires both that Agent's connection and your identity. Authorizing the same external account for a second Agent creates a separate connection with its own consent.
**Credentials entered in Admin or on a setup page never enter model context or the tool arguments the model writes.** The model picks a connection by ID and the secret goes in at egress. The exception is a key a person pastes into a Slack message. That key is message text, so the Agent reads it and may pass it to `try_connection` or `save_connection_key`. Chickpea accepts it only from that person's own message, when they may edit the Agent, sends it only to URLs under the hosts and paths they typed beside it or approved in that conversation in the last 30 minutes, and saves it only into an API connection that has no key yet, after a test request with it succeeds. The key stays in the Slack message, so the Agent suggests rotating it. An interrupted OAuth flow resumes bound to the provider, the account owner, the Agent, and the Slack task it left. Disconnecting revokes that one connection, tombstones secret access, and retires it from dependent schedules.
Selected connection capabilities authorize the Agent to carry out the requested task. The model uses the conversation and saved instructions to determine intent, without requiring particular words or an extra confirmation merely because a tool can write. Explicit read-only permissions, preview-only requests, and saved confirmation requirements remain in force. Conversation text and API results cannot expand connection grants. The [Security Model](#security-model) has the full list.
What you can connect, 105 presets in all. 47 run through a single Composio key; the other 58 go through the vendor's hosted MCP server or a direct API:
<table>
<tr>
<th colspan="5" align="left">Managed · one Composio key</th>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/gmail" width="14" height="14" alt=""> Gmail</td>
<td><img src="https://cdn.simpleicons.org/googlecalendar" width="14" height="14" alt=""> Google Calendar</td>
<td><img src="https://cdn.simpleicons.org/googledrive" width="14" height="14" alt=""> Google Drive</td>
<td><img src="https://cdn.simpleicons.org/googlesheets" width="14" height="14" alt=""> Google Sheets</td>
<td><img src="https://cdn.simpleicons.org/googledocs" width="14" height="14" alt=""> Google Docs</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/googleslides" width="14" height="14" alt=""> Google Slides</td>
<td><img src="https://cdn.simpleicons.org/googlesearchconsole" width="14" height="14" alt=""> Search Console</td>
<td><img src="https://cdn.simpleicons.org/googleanalytics" width="14" height="14" alt=""> Google Analytics</td>
<td><img src="https://cdn.simpleicons.org/notion/000000/ffffff" width="14" height="14" alt=""> Notion</td>
<td><img src="https://cdn.simpleicons.org/hubspot" width="14" height="14" alt=""> HubSpot</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/googleads" width="14" height="14" alt=""> Google Ads</td>
<td><img src="https://cdn.simpleicons.org/youtube" width="14" height="14" alt=""> YouTube</td>
<td>Gong</td>
<td>Freshdesk</td>
<td><img src="https://cdn.simpleicons.org/bitbucket" width="14" height="14" alt=""> Bitbucket</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/box" width="14" height="14" alt=""> Box</td>
<td><img src="https://cdn.simpleicons.org/caldotcom" width="14" height="14" alt=""> Cal.com</td>
<td>Canva</td>
<td><img src="https://cdn.simpleicons.org/contentful" width="14" height="14" alt=""> Contentful</td>
<td><img src="https://cdn.simpleicons.org/dropbox" width="14" height="14" alt=""> Dropbox</td>
</tr>
<tr>
<td>Dynamics 365</td>
<td>Excel</td>
<td><img src="https://cdn.simpleicons.org/figma" width="14" height="14" alt=""> Figma</td>
<td><img src="https://cdn.simpleicons.org/github" width="14" height="14" alt=""> GitHub</td>
<td><img src="https://cdn.simpleicons.org/googlebigquery" width="14" height="14" alt=""> Google BigQuery</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/googlemeet" width="14" height="14" alt=""> Google Meet</td>
<td><img src="https://cdn.simpleicons.org/googletasks" width="14" height="14" alt=""> Google Tasks</td>
<td>Gorgias</td>
<td>Klaviyo</td>
<td><img src="https://cdn.simpleicons.org/mailchimp/241C15/FFE01B" width="14" height="14" alt=""> Mailchimp</td>
</tr>
<tr>
<td>Microsoft Teams</td>
<td>OneDrive</td>
<td>Outlook</td>
<td><img src="https://cdn.simpleicons.org/pagerduty" width="14" height="14" alt=""> PagerDuty</td>
<td><img src="https://cdn.simpleicons.org/pinterest" width="14" height="14" alt=""> Pinterest Ads</td>
</tr>
<tr>
<td>Pipedrive</td>
<td><img src="https://cdn.simpleicons.org/quickbooks" width="14" height="14" alt=""> QuickBooks</td>
<td><img src="https://cdn.simpleicons.org/reddit" width="14" height="14" alt=""> Reddit Ads</td>
<td>Salesforce</td>
<td><img src="https://cdn.simpleicons.org/semrush" width="14" height="14" alt=""> Semrush</td>
</tr>
<tr>
<td>SharePoint</td>
<td><img src="https://cdn.simpleicons.org/square" width="14" height="14" alt=""> Square</td>
<td><img src="https://cdn.simpleicons.org/trello" width="14" height="14" alt=""> Trello</td>
<td><img src="https://cdn.simpleicons.org/webex" width="14" height="14" alt=""> Webex</td>
<td>Wrike</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/zoho" width="14" height="14" alt=""> Zoho CRM</td>
<td><img src="https://cdn.simpleicons.org/zoom" width="14" height="14" alt=""> Zoom</td>
</tr>
<tr>
<th colspan="5" align="left">Presets · the vendor's hosted MCP server, with OAuth or an API key</th>
</tr>
<tr>
<td>Adzviser</td>
<td>Ahrefs</td>
<td><img src="https://cdn.simpleicons.org/airtable" width="14" height="14" alt=""> Airtable</td>
<td>Amplitude</td>
<td>Apollo.io</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/atlassian" width="14" height="14" alt=""> Atlassian</td>
<td>Attio</td>
<td><img src="https://cdn.simpleicons.org/betterstack/000000/ffffff" width="14" height="14" alt=""> Better Stack</td>
<td>BugSnag</td>
<td><img src="https://cdn.simpleicons.org/calendly" width="14" height="14" alt=""> Calendly</td>
</tr>
<tr>
<td>Clay</td>
<td><img src="https://cdn.simpleicons.org/clickhouse" width="14" height="14" alt=""> ClickHouse</td>
<td><img src="https://cdn.simpleicons.org/clickup" width="14" height="14" alt=""> ClickUp</td>
<td>Close</td>
<td><img src="https://cdn.simpleicons.org/cloudflare" width="14" height="14" alt=""> Cloudflare</td>
</tr>
<tr>
<td>Customer.io</td>
<td><img src="https://cdn.simpleicons.org/datadog" width="14" height="14" alt=""> Datadog</td>
<td>Exa</td>
<td>Fathom</td>
<td>Firecrawl</td>
</tr>
<tr>
<td>Fireflies</td>
<td>Gamma</td>
<td><img src="https://cdn.simpleicons.org/gitlab" width="14" height="14" alt=""> GitLab</td>
<td><img src="https://cdn.simpleicons.org/grafana" width="14" height="14" alt=""> Grafana Cloud</td>
<td>Granola</td>
</tr>
<tr>
<td>Honeycomb</td>
<td><img src="https://cdn.simpleicons.org/huggingface" width="14" height="14" alt=""> Hugging Face</td>
<td>incident.io</td>
<td><img src="https://cdn.simpleicons.org/intercom/000000/ffffff" width="14" height="14" alt=""> Intercom</td>
<td><img src="https://cdn.simpleicons.org/linear" width="14" height="14" alt=""> Linear</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/lucid/282C33/ffffff" width="14" height="14" alt=""> Lucid</td>
<td>LunarCrush</td>
<td>Mercury</td>
<td><img src="https://cdn.simpleicons.org/meta" width="14" height="14" alt=""> Meta Ads</td>
<td><img src="https://cdn.simpleicons.org/miro/050038/ffffff" width="14" height="14" alt=""> Miro</td>
</tr>
<tr>
<td>Monday.com</td>
<td>MotherDuck</td>
<td>Neon</td>
<td><img src="https://cdn.simpleicons.org/netlify" width="14" height="14" alt=""> Netlify</td>
<td>Otter.ai</td>
</tr>
<tr>
<td>PandaDoc</td>
<td><img src="https://cdn.simpleicons.org/paypal" width="14" height="14" alt=""> PayPal</td>
<td>Plain</td>
<td><img src="https://cdn.simpleicons.org/posthog" width="14" height="14" alt=""> PostHog</td>
<td>Pylon</td>
</tr>
<tr>
<td>Read AI</td>
<td><img src="https://cdn.simpleicons.org/sentry/362D59/ffffff" width="14" height="14" alt=""> Sentry</td>
<td>Statsig</td>
<td><img src="https://cdn.simpleicons.org/stripe" width="14" height="14" alt=""> Stripe</td>
<td><img src="https://cdn.simpleicons.org/supabase" width="14" height="14" alt=""> Supabase</td>
</tr>
<tr>
<td>Supermetrics</td>
<td><img src="https://cdn.simpleicons.org/tiktok/000000/ffffff" width="14" height="14" alt=""> TikTok Ads</td>
<td><img src="https://cdn.simpleicons.org/todoist" width="14" height="14" alt=""> Todoist</td>
<td><img src="https://cdn.simpleicons.org/webflow" width="14" height="14" alt=""> Webflow</td>
<td>Windsor.ai</td>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/wix" width="14" height="14" alt=""> Wix</td>
</tr>
<tr>
<th colspan="5" align="left">Presets · direct HTTP API</th>
</tr>
<tr>
<td><img src="https://cdn.simpleicons.org/asana" width="14" height="14" alt=""> Asana</td>
<td><img src="https://cdn.simpleicons.org/zendesk/03363D/ffffff" width="14" height="14" alt=""> Zendesk</td>
<td colspan="3"></td>
</tr>
<tr>
<th colspan="5" align="left">Native · bring your own</th>
</tr>
<tr>
<td colspan="5">Any service with an HTTP API or a remote MCP server. Bearer tokens and custom headers supported.</td>
</tr>
</table>
<sub>Gmail, Google Calendar, and Google Drive can also connect through your own Google Cloud OAuth client instead of Composio.</sub>
Managed connectors run through one Composio project key, added under **Settings → Connectors**. Sign-in happens in Composio's hosted UI and Chickpea polls for completion, so a self-hosted install needs no public OAuth callback URL. Opting in means Composio holds OAuth storage, refresh, and API execution for those accounts; Chickpea still owns account selection, capability limits, the read or read-and-write lane of each connection, and which provider account is used on every call. See the [managed connector runbook](docs/runbooks/composio-managed-connectors.md).
---
## Managing Chickpea
Chickpea has an Admin panel. It is not the only way in. The same controls have three front doors, with the same permissions and the same approvals behind each one.
- **Admin**, the browser UI on your deployment.
- **Slack**, by asking `@Chickpea`, or asking any Agent about itself.
- **[MCP](#connect-via-mcp)**, from any MCP client you already use, through the management MCP server. Settings → MCP in Admin has the snippet for each client, and `https://<your Chickpea>/connect` has the one-line prompt.
Most days the Slack door is the one you want.
> **`@Chickpea`** make me a support agent that answers billing questions and knows our refund policy
That one message creates the Agent, gives it a handle and an avatar, and publishes it to a channel you name. Where each job can be done:
| | Slack | Admin | MCP |
|---|:---:|:---:|:---:|
| Create, edit, archive, and restore Agents | ✓ | ✓ | ✓ |
| Change an Agent's instructions, model, or handle | ✓ | ✓ | ✓ |
| Publish an Agent to a channel, or pull it out | ✓ | ✓ | ✓ |
| Import skills from a GitHub repo or a `skills.sh` link | ✓ | ✓ | ✓ |
| Edit an Agent's memory | ✓ | ✓ | ✓ |
| Set up and manage schedules | ✓ | ✓ | ✓ |
| Connect a service, grant a repository, add a provider key | link | ✓ | link |
| Composio project key, GitHub App, coding sandbox install | | ✓ | |
"Link" means the Agent hands back a Chickpea link and the rest finishes in the browser, where OAuth sign-in and secret entry happen. Two exceptions take an API key directly: a key a person pastes in Slack, under the rules in [Connections and Authority](#connections-and-authority), and a key a person gives an MCP client, which reaches Chickpea in that client's tool call with the person's own Admin authority and may replace a saved key. When you hand an Agent a GitHub link for skills, it reads the `SKILL.md` files and shows you which skills it found before importing any of them.
What keeps a chat window from being a loophole:
- **Who can change what.** `@Chickpea` can create Agents and edit any Agent you're permitted to edit. A routed Agent can inspect and edit only itself, still bound by your permissions.
- **Proposals before consequences.** Two kinds of change arrive as a frozen read-only proposal: anything the Agent inferred rather than you stated, and anything that changes what an Agent can do, reach, or delete. Nothing applies until you approve it.
- **No ceremony for small edits.** Simple reversible single-field changes apply directly, and you can undo them.
- **MCP gets the same treatment.** Requests are scoped to that requester's permissions and held to the same approvals. The authoring guide is published at `chickpea://guide/agent-authoring/v1`, and the [workspace management MCP runbook](docs/runbooks/workspace-management-mcp.md) covers authority and proposal semantics.
### CLI
For scripts, there is a fourth door: the official [`chickpea-cli`](packages/cli/README.md) package on npm. It signs in with the same OAuth flow an MCP client uses and calls the same management tools, so a deployment can be checked and configured from a shell without building an MCP integration.
```bash
npx chickpea-cli doctor https://chickpea.example.com # public checks, no sign-in
npx chickpea-cli mcp config https://chickpea.example.com # client config for Claude Code, Codex, Cursor, and more
npx chickpea-cli login https://chickpea.example.com # browser sign-in, tokens stored 0600
npx chickpea-cli workspace inspect https://chickpea.example.com
npx chickpea-cli call https://chickpea.example.com <tool> --args '{...}'
npx chickpea-cli recipe export https://chickpea.example.com > recipe.json
npx chickpea-cli skills upload https://chickpea.example.com agent_support skills.zip
```
The CLI never takes a token or key as an argument, never confirms a proposal on its own, and sends no telemetry. Node 24.x, minimum 24.22.1.
---
## Memory
One memory per Agent, no partitions. The same body informs its DMs and every granted channel.
One consequence of that: **something learned in a private conversation can influence a later channel answer.** If you need isolation, use a separate Agent. Memory is not it.
Memory is advisory, never policy. Live instructions, current permissions, and verified grant state win. Memory refuses credentials such as API keys and tokens, whether it is written from Admin, Slack, or MCP. The model reads it as context that cannot grant authority, and memory text cannot break out of that frame.
---
## Schedules
Schedules belong to an Agent, target a granted Slack destination or a private DM thread, and record their creator as **Runs as**. Ask for one in Slack and the Agent sets it up.
Every run rechecks the whole chain: is the Agent alive, does it still have the channel, is the creator still a member, do the required connections still work, does policy still allow it. If authority disappears, future runs pause. Chickpea never silently reassigns work to someone else. Cloudflare supplies alarms; the production Node launcher checks for due work at startup and every minute while its process is running.
---
## Models and Providers
Bring your own: Anthropic, OpenAI, Google Gemini, OpenRouter, or Cloudflare Workers AI. Cloudflare deploys can use the keyless binding provider and skip the API token entirely. Keys go in environment variables or in Settings, whichever you prefer.
Google Gemini offers Gemini 4 Argon, Gemini 3.8 Flash and Gemini 3.5 Flash-Lite. Use a key from a Google Cloud project with billing turned on: Google may use prompts sent with free-tier keys to improve its products. Turn off request logging for the project in Google AI Studio.
Node installations can also connect a ChatGPT subscription in **Settings → Model providers → OpenAI** for chat. This uses the subscription's shared usage limits. The option is unavailable on Cloudflare. Switching between a subscription and an API key is explicit; Chickpea does not fall back to API billing when the subscription is unavailable.
Every Agent can be pinned to its own model. A cheap fast model for triage, a strong one for the Agent that writes.
For models that support it, the workspace default, the coding model, and each pinned Agent also take an effort level, from Low to Max. Higher effort thinks longer before answering, so it is slower and uses more tokens; the default is the model's standard level, and an Agent that follows the workspace default uses its effort too.
Images are a second model role beside chat. The first OpenAI connection sets an unconfigured workspace image default: **GPT Image 2.6 Flare** when you add an API key, or **ChatGPT Image** when you connect a subscription on Node. Existing choices, including a deliberately cleared default, are preserved. Change the **default image model** in **Settings → Model providers**, or override it on any Agent from its Model tab; Agents with the role filled can generate images in a thread, and Agents without it cannot. Flare and Sunburst, in versions 2.6 and 2.5, use your OpenAI API key and support editing images from the conversation. The 2.5 models stay available and cost less per image, except at high quality and above. On Node, **ChatGPT Image** uses the connected ChatGPT subscription independently of the selected chat method; it generates one image per call and does not edit images. ChatGPT chooses its output settings and does not identify a specific underlying image model. When an Agent makes an image, the prompt text it writes and any supported images people posted in that Slack thread are sent to that provider.
With Flare or Sunburst, ask for square, portrait, or landscape output, a quick draft, or a transparent background; the Agent passes explicit output controls. With ChatGPT Image, those preferences travel in the prompt and ChatGPT chooses the output settings. The Agent checks the returned file's dimensions and transparency. For models that support editing, a visual check uses the Agent's configured chat model and may make one corrective edit within the four-image response budget. Visual inspection can miss defects; it does not establish pixel-identical logos or typography, and unavailable checks are reported.
Chickpea attempts to retain generated files up to 8 MiB privately for up to 24 hours. The installation shares a 64 MiB cache; each file is accessible only in its workspace, Agent, channel, and thread. Cache pressure may remove files earlier. Ask to resend a retained image to retry its delivery without generating it again. Oversized files are compressed. For Flare and Sunburst, explicitly requested dimensions are preserved unless you accept a smaller resend. An image already shared in the conversation is resent using its original Slack file, avoiding another upload that Slack may re-encode. A new name labels the link; the existing download filename stays unchanged. Generated outputs and their references are also sent to the configured chat provider for the visual check. Transparent images are shown against a neutral checkerboard for inspection only; this does not alter the delivered file. Image generation and inspection costs are not yet included in Usage.
---
## Coding Sandbox
The default Cloudflare deploy is the **core profile**: no container, no image build, small and fast. Normal Slack replies, administration, GitHub browsing, and repository-aware model work need none of it.
Install the coding sandbox when an Agent needs a real checkout, package installation, tests, or a dev server. Open **Settings → Coding sandbox**, request installation, redeploy. It requires **Workers Paid**. The container application and its Ubuntu-based image live in your Cloudflare account and may incur costs on it, and the first image build takes several minutes. Node installations always use the standard in-memory bash sandbox and never touch the host filesystem or host git and SSH. Full procedure in the [coding sandbox runbook](docs/runbooks/coding-sandbox-deployment.md).
---
## Security Model
What the design guarantees:
- **No ambient listening.** Unmentioned root messages never trigger classification, model spend, memory writes, or work. There is no "read the channel and decide if you're needed" mode.
- **Credentials entered in Admin or on a setup page never reach the model.** Never in model context, never in the tool arguments the model writes. The model picks a connection by ID; the runtime resolves the secret at the moment of the call and injects it at egress. A key a person pastes into a Slack message is the exception. The Agent reads it as message text and may pass it to the tool that tests or saves it, under the rules in [Connections and Authority](#connections-and-authority).
- **Conversation cannot expand authority.** Authority comes from stored grants and saved instructions, read from stored state and re-checked at the moment of each use, never from anything produced during the turn. Message text, retrieved content, and tool output are data, never permission.
- **Connection permissions**, enforced through selected tools, resource scopes, and argument restrictions. Saved confirmation requirements and preview-only requests guide the model's behavior.
- **Per-Agent isolation.** Connections, memory, skills, repositories, and reach all stop at the Agent. Nothing is reused across Agents implicitly.
- **Slack OIDC is the only human sign-in.** No passwords. The first installer becomes the first Owner, bound to an exact workspace and user tuple. Email is mutable contact information, not the identity key. See [authentication](docs/authentication.md).
- **An editor may publish only to a channel they belong to.** Chickpea Admin status does not bypass Slack channel membership.
- **Self-hosted state.** Runtime, model traffic, configuration, memory, and connector credentials stay in infrastructure you operate. The exception is opting into Composio-managed connectors, which delegates OAuth storage, refresh, and API execution for those accounts to Composio. Native API and MCP connections keep their credentials with you.
- **Minimal product telemetry.** Chickpea sends six content-free, anonymous product events to measure adoption. It sends no messages, prompts, tool data, customer identity, or error text; it creates no person profile and can be disabled completely. The exhaustive field list and opt-out instructions are in [Product telemetry](TELEMETRY.md).
The other exception is the optional shared Slack-app gateway, which exists so you can skip Slack app configuration entirely. It stores encrypted installation credentials and sanitized health metadata, but does **not durably store Slack message or event bodies**. If it cannot hand an event to your deployment, it returns a failure so Slack can retry; with Slack's Delayed Events setting enabled, those retries can continue hourly for 24 hours. Cloudflare and Node deployments durably admit the event before acknowledging it, then scrub the body as soon as processing reaches a terminal state and keep only a content-free deduplication record for 48 hours. Node stores its inbox in the installation's SQLite state and receives deliveries over an outbound socket. Separately, your deployment keeps a bounded thread record for each Slack thread an Agent is part of: the Slack-visible messages there, with their authors, so the Agent can follow a long thread without rereading Slack. It holds at most 200 messages per thread, applies Slack edits and deletions, drops a thread after 30 days without activity, and keeps nothing for threads no Agent is in. Read the exact retention and recovery boundaries in [Shared Slack gateway data handling](docs/shared-gateway-data-handling.md). If you'd rather not have the gateway in the path at all, pick the customer-owned Slack app lane, which talks directly to your deployment and never loads the gateway client.
---
## Get started with your coding agent
<a id="install-with-your-coding-agent"></a>
### Install on Cloudflare
Copy this prompt into a coding agent with terminal and browser access:
```text
Install Chickpea for my Slack workspace on my Cloudflare account using this guide:
https://chickpea.co/install.md
```
The address serves the [installation guide](INSTALL_CHICKPEA_CLOUDFLARE.md),
which stays current on `main`. It has your agent pick the latest stable
release, walk you through the Cloudflare, Slack, and model-provider choices,
verify a real Slack reply and Admin sign-in, connect itself to your new
Chickpea over MCP, and report the installed release and local project path.
### Install on your Mac
Copy this prompt into a coding agent running on the Mac:
```text
Install Chickpea on this Mac using this guide:
https://chickpea.co/install-mac.md
```
The address serves the [Mac installation guide](INSTALL_CHICKPEA_NODE.md). It
handles Node, the build, private state, and starting Chickpea. You choose a
stable HTTPS address and complete Slack and provider authorization in your
browser, and the agent connects itself over MCP before it finishes. Prefer a
shell to an agent? The [one-line installer](#node) does the same job.
### Connect via MCP
Chickpea includes a built-in MCP server. Connect your coding agent to create
Chickpea Agents, update their instructions, manage connections, edit memory,
and set up schedules.
You need an existing Chickpea installation and permission to manage the Agents
you want to work with. Every address below uses your installation's address:
the same one you use for Admin, without `/admin`. Ask whoever installed
Chickpea if you don't know it.
The quickest way is to paste one line into your coding agent:
```text
Connect my coding agent to my Chickpea using https://<your Chickpea>/connect.md
```
The agent reads that guide from your own deployment, writes its own client
configuration, signs in through Slack, and proves the connection with one
read-only call. Two places give you that prompt with the real address filled
in, plus the exact snippet for every client:
- **Settings → MCP** in Admin (`https://<your Chickpea>/admin/settings/agents-clients`).
The Coding agents page lists Claude Code, Codex, Cursor, VS Code, Windsurf,
Gemini CLI, the Claude app, ChatGPT, and a generic JSON block, each with a
Copy button, plus one-click **Add to Claude**, **Add to Cursor**, and **Add
to VS Code**. Every member can open it.
- **`https://<your Chickpea>/connect`**, a public page on your deployment, for
anyone who is not signed in to Admin yet. It works before Slack setup is
finished, although `/mcp` answers 404 until setup completes.
Prefer to type it yourself? One example, for Claude Code, with
`chickpea.example.com` standing in for your address:
```bash
claude mcp add --transport http --scope user chickpea https://chickpea.example.com/mcp
```
Then open Claude Code, run `/mcp`, select `chickpea`, and follow the browser
sign-in steps. The Settings page has the equivalent for every other client.
#### Sign in and try it
Sign in with your Slack account for the workspace where Chickpea is installed,
then approve access to manage your Chickpea workspace. Authentication uses
OAuth; no API key or separate MCP package is needed, and you never create or
paste a token.
Start a conversation in your coding agent and ask:
> Use Chickpea to show me the Agents I can manage and their connected services.
Then try:
> Create a Chickpea Agent named Support that helps our team answer billing questions.
Not sure what your first Agent should do? Ask:
> What should I build with Chickpea?
Your coding agent looks at your recent projects and sessions on this machine
and proposes one Agent built on work you already do, naming what it looked at.
Nothing it reads is sent to Chickpea. When you say yes, it creates the Agent,
which then sends you a message in Slack.
In Claude Code, `/mcp__chickpea__new-agent` opens the same guided flow from the
slash menu; `/mcp__chickpea__status`, `/mcp__chickpea__edit-agent`, `/mcp__chickpea__connect`,
`/mcp__chickpea__schedule`, and `/mcp__chickpea__import-skill` cover the rest.
These are MCP prompts, not installed local skills. In Codex, ask for the same
work in plain language; they do not appear in the `$` skills picker. No separate
skills installation is required in either client.
Chickpea applies your existing permissions. Changes that expand access or
require confirmation produce a proposal for you to approve. Connecting an
account opens a browser setup flow.
Other MCP clients can connect to the same `/mcp` URL using Streamable HTTP
and OAuth.
See [Managing Chickpea](#managing-chickpea) for available controls and the
[MCP guide](docs/runbooks/workspace-management-mcp.md) for details.
<a id="update-with-your-coding-agent"></a>
### Update Chickpea
Open your Chickpea folder in your coding agent and paste:
```text
Update this Chickpea installation to the latest stable release. Follow:
https://chickpea.co/update.md
```
The address serves the [update guide](UPDATE_CHICKPEA_CLOUDFLARE.md), which stays current on `main`. Your
coding agent preserves the existing installation settings, deploys the latest
release, and verifies Admin access. It does not send test messages to Slack.
<a id="uninstall-with-your-coding-agent"></a>
### Uninstall Chickpea
Open your Chickpea folder in your coding agent and paste:
```text
Uninstall this Chickpea installation. Follow:
https://github.com/pejmanjohn/chickpea/blob/main/UNINSTALL_CHICKPEA_CLOUDFLARE.md
```
The address serves the [uninstall guide](UNINSTALL_CHICKPEA_CLOUDFLARE.md),
which stays current on `main`. Your coding agent lists exactly what it will
remove and waits for you to confirm before deleting anything. It then removes
Chickpea from Slack, deletes the Worker and its database from Cloudflare, and
disconnects itself from your installation. Deletion is permanent.
---
<a id="install"></a>
## Deploy it yourself
### Cloudflare
The Worker upload fits comfortably within Cloudflare's platform-wide size limit; only the optional coding sandbox requires Workers Paid. See [Good to Know](#good-to-know).
The [installation guide](INSTALL_CHICKPEA_CLOUDFLARE.md) is written for a coding agent, but every step in it is an ordinary command or browser action you can carry out yourself: clone a release tag, install dependencies, authorize Wrangler, deploy, and open the private setup link it prints.
Then pick a Slack lane:
- **Add to Slack** installs the unlisted shared Chickpea app through the private gateway. No configuration token, client secret, signing secret, public Events URL, or app-level token required from you.
- **Use your own Slack app** creates and installs a customer-owned app from the reviewed manifest. Paste a configuration token and it's done; a manual manifest path with screenshots is the fallback. Step-by-step in [SETUP_AGENT.md](SETUP_AGENT.md).
Setup then runs four steps: connect Slack, choose a provider, choose a model, and try it. The last step has you message Chickpea in Slack. A real reply is the proof.
App installation and browser sign-in are two different OAuth jobs. Installation grants bot scopes; sign-in requests `openid profile email` and binds you as the first Owner.
Uses Cloudflare Workers, Durable Objects, D1, and Workers AI.
### Node
On a Mac, run:
```sh
curl -fsSL https://chickpea.co/install.sh | bash
```
The installer prepares a private Node 24.22.1 runtime, builds a stable application
release, creates persistent SQLite state, and opens setup. It leaves system Node
and existing Chickpea installations alone. Guided ngrok setup can
provide a stable HTTPS address without buying a domain or using Cloudflare.
It saves your assigned domain and privately entered token, and runs the tunnel
alongside Chickpea. Cloudflare Tunnel and externally managed HTTPS remain options.
You need permission to install a Slack app and a model provider account. The
[Mac installation guide](INSTALL_CHICKPEA_NODE.md) explains the HTTPS options,
start/stop/restart commands, and optional start at login. ngrok Free has usage
limits and a browser warning; check its current account allowance before relying
on it for ongoing traffic.
The installer uses the latest stable application release. Mac installation is
supported starting with v0.1.21. Guided ngrok setup and support for the shared
Chickpea Slack app on Node are available starting with v0.1.22.
For an existing manual installation, keep using
`npm run start:node -- --env-file <path>`. For Linux hosting, backups, restores,
and upgrades, use
[Operating and upgrading Chickpea](docs/runbooks/operations.md).
---
## Configuration
Chickpea is offline-safe by default. Left unset, most variables take a local path. These are the ones worth knowing:
| Variable | When | Purpose |
|---|---|---|
| `CHICKPEA_AUTH_SECRET` | required on Node, managed on Cloudflare | Stable internal signing authority. |
| `SLACK_SIGNING_SECRET` | customer-owned Slack lane | Verifies direct Events API requests. Setup can store it instead. |
| `SLACK_BOT_TOKEN` | customer-owned Slack lane | Direct Slack Web API credential. Setup can store it instead. |
| `CHICKPEA_GATEWAY_URL` | optional | Shared-app gateway origin. Defaults to the Chickpea-operated service; override only for a compatible private gateway. |
| `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GEMINI_API_KEY` / `OPENROUTER_API_KEY` | optional | Enable the matching provider. Can be stored in Settings instead. |
| `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_API_TOKEN` | optional | Enable REST Workers AI. Cloudflare deploys can use the keyless binding provider instead. |
| `COMPOSIO_API_KEY` | optional | Deployment-managed alternative to adding the project key in **Settings → Connectors**. Never enters a runtime plan or model context. |
| `EXA_API_KEY` | optional | Gives Agents web search through Exa. Without it, Agents still read web pages but cannot search. Never enters a runtime plan or model context. |
| `DO_NOT_TRACK` / `CHICKPEA_DISABLE_TELEMETRY` | optional | Set either to `1`, `true`, or `yes` to disable anonymous [product telemetry](TELEMETRY.md) completely. |
| `CHICKPEA_TELEMETRY_ENVIRONMENT` | optional | Label telemetry as `production`, `development`, or `test`; defaults to production on Cloudflare and development on Node. |
| `CHICKPEA_RESIDENCY_HOLD_MS` | optional, Cloudflare | Keeps a conversation's Durable Objects in memory for this many milliseconds (at most 900000) after each turn, so follow-ups skip a cold start. Off by default. Held objects are billed, and Workers Free's daily duration limit can run out; read [the conditions](docs/runbooks/operations.md#hold-a-conversations-objects-in-memory) first. |
| `CHICKPEA_SLACK_ADMISSION` | optional, Cloudflare | `store` has a direct installation's state store admit its Slack messages and mentions, in one call from the Worker, instead of the Worker admitting them over many calls to the store. Off by default. Read [the conditions](docs/runbooks/operations.md#admit-slack-messages-in-the-state-store) first. |
| `TAG_DB_PATH` / `SLACK_STATE_DB_PATH` | optional, Node | SQLite paths for durable transcripts and app-owned state. |
| `CHICKPEA_RECOVERY_TOKEN` | optional break-glass | One short-lived repair capability. Not a login credential. |
The full list, including per-connector Composio auth config IDs and the Google Ads and YouTube quota and policy assertions, is documented in [.env.example](.env.example), with setup procedures in the [managed connector runbook](docs/runbooks/composio-managed-connectors.md) and repair steps in the [Slack auth recovery runbook](docs/runbooks/slack-auth-recovery.md).
---
## Good to Know
- One deployment currently serves one Slack workspace.
- The shared gateway is private infrastructure. Its implementation and Slack credentials are not in this public repository, and it does not durably queue Slack event bodies. Delivery recovery relies on Slack retries plus deployment-owned admission; [the data-handling contract](docs/shared-gateway-data-handling.md) spells out what is stored, where, and for how long.
- Updates are manual. The [update guide](UPDATE_CHICKPEA_CLOUDFLARE.md) walks a coding agent through them; your installation is a clone of a release tag, not a fork.
- Node durability is single-host SQLite. Multi-instance Node needs a shared state service.
- The Worker upload is about 10 MiB uncompressed, well under Cloudflare's 64 MiB platform-wide limit; `npm run build` fails if it grows past the budget in `scripts/verify-worker-size.mjs`. Public images and the Admin application's browser code use Static Assets in the same deployment, which do not count toward that limit. Workers Free still caps CPU time and request volume, and the optional coding sandbox requires Workers Paid.
- Anonymous, content-free [product telemetry](TELEMETRY.md) is enabled by default and has a complete operator opt-out.
- The coding sandbox is Cloudflare-only. Node uses the in-memory execution path and runs scheduled work only while its production process is active; startup applies the same eligible missed-run policy after downtime.
- Earlier experimental schemas may be incompatible. Never reset production state to upgrade; follow the [compatibility and recovery policy](docs/runbooks/operations.md#upgrade-and-compatibility-policy).
Contributions go through GitHub pull requests; see [CONTRIBUTING.md](CONTRIBUTING.md).
Report vulnerabilities privately using [SECURITY.md](SECURITY.md). Maintainers
use the [release checklist](docs/runbooks/releasing.md).
<details>
<summary><strong>Attachment limits</strong></summary>
Per turn: 10 files, 8 MiB each, 12 MiB total, 100 PDF pages, 64,000 characters per file and 128,000 total. Images use Slack's bounded thumbnails when available. Anything over a limit, or without a safe conversion, gets a file-specific next action instead of a quiet partial read. Slack installations predating the `files:read` scope must reconnect once.
Reading a file on request: the newest 20 files in a conversation, 8 MiB per download, 20 reads per turn, and 50,000 characters per page. A zip holds at most 2,000 files, and a file inside unpacks to at most 8 MiB.
</details>
---
## FAQ
**"Why not just run one bot with every tool connected?"**
Because then every channel that bot is in has every credential that bot holds, and everything it learns anywhere it can say anywhere. Agents exist so you can put a wall between support's Zendesk and finance's spreadsheets without running a second deployment.
**"What does this cost to run?"**
Chickpea itself is licensed under Apache 2.0 with no per-seat pricing and no metering. You pay your model provider directly for API usage. The Worker upload fits comfortably within Cloudflare's platform-wide size limit; the optional coding sandbox requires Workers Paid. Workers, Durable Objects, D1, Workers AI, and optional coding sandbox usage run in your own Cloudflare account and may incur costs. Running on your own Node host, the infrastructure bill is whatever that host costs you.
**"How do I see what an Agent actually did?"**
Most of it is already visible: work happens in Slack threads, in the open, under the Agent's own name. In Admin, the Memory tab shows exactly what an Agent retained (and lets you edit or delete it), and the Schedules tab shows status, last run, next run, and a run-history and activity inspector for scheduled work. One deliberate gap: activity telemetry is fixed-schema and content-free, and Admin has no searchable conversation archive. The conversation itself lives in Slack and in your deployment's transcript store.
**"What is Flue?"**
The open agent framework Chickpea runs on: [`@flue/runtime`](https://www.npmjs.com/package/@flue/runtime) · [flueframework.com](https://flueframework.com) · [github.com/withastro/flue](https://github.com/withastro/flue). Apache-2.0, from the Astro team, now part of Cloudflare. Flue is the TypeScript harness; Chickpea is the Slack product on top of it. More in [How It Works](#how-it-works).
---
## Development
```bash
npm install
npm test # typecheck + node --test over tests/
npm run dev # local Node lane
npm run build # Cloudflare build
```
Targeted checks worth knowing:
```bash
npm run verify:admin-ui
npm run verify:cf-smoke
npm run verify:providers
npm run verify:management-mcp
npm run verify:oss-export
```
Node **24.22.1** is pinned in `.nvmrc` for development, builds, and verification. Node 24.x is the only supported major, with engine range `>=24.22.1 <25`. Later Node 24 updates are supported; update the pin for patch/security releases and verify the new baseline once. Other Node majors are outside this release's support policy. Several `verify:*:live` variants exist for provider- and Slack-touching evaluations; they are opt-in because they spend real quota. Live Slack acceptance should run against a disposable paid workspace so user-group policy, handle collisions, public auto-join, private invitation, App Home, avatar updates, archive, and restore all get exercised for real.
Live Slack verification is available through the repo-scoped [`$chickpea-live-verification`](.agents/skills/chickpea-live-verification/SKILL.md) skill. Codex discovers it automatically in this repository. The thin entry point routes to the [canonical operator workflow](qa/live/operator/SKILL.md) and [runbook](docs/runbooks/live-contract-verification.md), so the operating instructions remain in one place.
`verify:slack-streaming-policy` validates the content-free model-decision fixture corpus. A
provider evaluation is deliberately separate and opt-in: run
`npm run verify:slack-streaming-policy:live -- --live --lane <lane> --model <id>` only when
quota use has been approved. It exercises the shipped `stream_answer` name, description,
instruction, and acknowledgement against clear positive, clear negative, and ambiguous Slack
requests under a reduced prompt and tool surface. Its paired timings are provider-boundary
proxies: they show whether the declaration round trip can beat terminal model completion, but
they do not include durable persistence or Slack transport. The command never calls Slack or
prints model output. Actual first-visible Slack latency remains a separate, approved disposable-
workspace launch gate. Re-run both checks for each supported model when the model, system
instruction, or tool protocol changes.
---
## License
[Apache License 2.0](LICENSE). Use it, fork it, run it for your company, sell what you build on it, subject to the license terms.
Copyright (c) 2026 Pejman Pour-Moezzi. See [NOTICE](NOTICE).
## Version and updates
Installation Owners can open **Settings → About & updates** to review the current
version, check releases, and copy an exact upgrade command. Updates are manual.
Start with the [Cloudflare update guide](UPDATE_CHICKPEA_CLOUDFLARE.md). The
[updater runbook](docs/runbooks/upgrading.md) documents its compatibility and
recovery boundaries. Node deployments follow the [operations guide](docs/runbooks/operations.md).