# Attach or update an agent MCP server Source: https://docs.gumloop.com/api-reference/agents/attach-agent-mcp-server put /agents/{agent_id}/mcp-servers/{server_id} Attach an MCP server (connector) to an agent, or update its configuration if it's already attached (upsert). The `server_id` is validated against the caller's MCP catalog. Catalog identity fields (`type`, `server_id`, `secret_id`, `mcp_server_url`) always come from the catalog and cannot be spoofed via the request body — the body carries only free-form connector configuration (e.g. approval mode, tool restrictions); any identity keys in it are ignored. Attach may succeed before OAuth is completed; `auth_status` reflects the catalog's authentication state. # Create agent Source: https://docs.gumloop.com/api-reference/agents/create-agent post /agents Create a new agent. The authenticated caller must have permission to create agents on the target team. # Detach an agent MCP server Source: https://docs.gumloop.com/api-reference/agents/detach-agent-mcp-server delete /agents/{agent_id}/mcp-servers/{server_id} Detach an MCP server (connector) from an agent. This is idempotent — detaching a server that isn't attached returns `detached: false` rather than an error. # List agent MCP servers Source: https://docs.gumloop.com/api-reference/agents/list-agent-mcp-servers get /agents/{agent_id}/mcp-servers List the MCP servers (connectors) attached to an agent. Sensitive fields such as `secret_id` and `mcp_server_url` are scrubbed from the response. # List agent versions Source: https://docs.gumloop.com/api-reference/agents/list-agent-versions get /agents/{agent_id}/versions List the immutable versions of an agent, newest first. Each entry is a point-in-time snapshot of the agent's configuration. Requires configuration access on the agent — callers limited to using the agent (no configuration access) get a `403`. # List agents Source: https://docs.gumloop.com/api-reference/agents/list-agents get /agents List agents the caller has access to. Filter by team, search by name, or narrow to agents that use a specific tool or trigger. Results can be sorted with `sort_order` and paginated by sending `page_size` and/or `cursor`. # Retrieve agent Source: https://docs.gumloop.com/api-reference/agents/retrieve-agent get /agents/{agent_id} Retrieve a single agent by ID. In addition to regular agent IDs, `agent_id` accepts the reserved aliases `gumball` (your personal Gumball agent) and `analytics` (your analytics agent) on all agent-scoped endpoints. The alias resolves to your own copy of the platform agent, creating it on first use, and responses report the alias back as the agent's `id`. # Retrieve agent version Source: https://docs.gumloop.com/api-reference/agents/retrieve-agent-version get /agents/{agent_id}/versions/{version_id} Retrieve one immutable agent version: its full configuration (`composition`) plus the structured `changes` relative to the version before it. Use it to export an agent's configuration or to audit what changed between versions. `changes` is `null` for the first version of an agent, since there is no predecessor to diff against. Versions created before attachment snapshots were recorded report `composition.complete: false` (and `changes.attachment_changes_complete: false`); their `skill_ids` and `knowledge_sources` are `null` rather than empty. Skill file contents are never included, and this endpoint is read-only — it cannot restore or deploy a version. Requires configuration access on the agent — callers limited to using the agent (no configuration access) get a `403`. # Update agent Source: https://docs.gumloop.com/api-reference/agents/update-agent patch /agents/{agent_id} Update an existing agent. Only fields included in the request body are changed; omitted fields are left untouched. This endpoint edits document fields only. To attach or detach skills, use [`PATCH /agents/{agent_id}/skills`](/api-reference/agents/update-agent-skills); to manage MCP servers, use the [agent MCP server endpoints](/api-reference/agents/attach-agent-mcp-server). **`is_active: false` is not a pause switch.** It retires the agent: the agent disappears from `GET /agents`, and both `GET` and `PATCH /agents/{agent_id}` return `404` afterwards, so you cannot set it back to `true` through the API. To stop an agent from running on its own while keeping it fully reachable, disable its [triggers](/core-concepts/agent_triggers#managing-active-triggers) instead. # Attach or detach agent skills Source: https://docs.gumloop.com/api-reference/agents/update-agent-skills patch /agents/{agent_id}/skills Attach and/or detach skills on an agent using deltas. This is **not** a replace-list: skills you don't mention are left untouched. - The operation is idempotent. Re-attaching a skill that's already attached (or detaching one that isn't) is reported under `already_attached` / `already_detached` rather than failing. - A skill ID may not appear in both `attach` and `detach`. - Up to 100 unique skill IDs total (`attach` + `detach`) per request. - Attaching requires `INVOKE` permission on the skill. Detaching is permissive so stale attachments can always be removed. # Download artifact Source: https://docs.gumloop.com/api-reference/artifacts/download-artifact get /artifacts/{artifact_id}/download Returns a signed download URL for an artifact, plus its filename, media type, and size. Follow `download_url` to fetch the file bytes. # List artifacts Source: https://docs.gumloop.com/api-reference/artifacts/list-artifacts get /agents/{agent_id}/artifacts List artifacts (files) produced by an agent. Optionally scope to a specific session, search by filename, sort, and paginate. Deleted files are excluded from the results. # Authentication Source: https://docs.gumloop.com/api-reference/authentication The Gumloop API supports two authentication methods. Both grant the same permissions and work on every endpoint — pick whichever matches how your app gets the credential. ## API key For scripts and integrations you control end to end. Generate one from the [Connectors page](https://www.gumloop.com/settings/profile/connectors?view=connected\&search=Gumloop+API+Key), then pass it as a bearer token. ```bash theme={"dark"} curl https://api.gumloop.com/api/v1/start_agent \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"user_id": "xxxxxxxxxxxx", "gummie_id": "xxxxxxxxxxxx", "message": "Hello"}' ``` API keys require the [Pro plan or above](https://www.gumloop.com/pricing). ### Personal vs Team keys Gumloop offers two flavors of API key, selectable when you generate one. | | Personal key | Team key | | - | - | - | | Acts as | The owning user only | Any team member (set `user_id` per request) | | Default credentials | The user's personal credentials | The credentials configured per workflow step (`Personal Default` or `Team Default`) | | Use when | Solo use, local development | Team automations, server-to-server, CI/CD | When a request includes `project_id`, each workflow step's *Credentials to use* setting decides whether the run uses the calling user's personal credentials or the team's credentials. The API parameter is still named `project_id` for backwards compatibility — it's the same thing the UI now calls your **team** ID. You can find your `user_id` on the [Profile Settings page](https://www.gumloop.com/settings/profile/general). See [Finding Your User ID](/api-reference/getting-started#finding-your-user-id) for details. ## OAuth 2.0 If you're building an app that other Gumloop users sign in to, use [OAuth 2.0](/api-reference/oauth). Once you've completed the flow and have an access token, pass it the same way: ```bash theme={"dark"} curl https://api.gumloop.com/api/v1/agents \ -H "Authorization: Bearer ACCESS_TOKEN" ``` # Approve source Source: https://docs.gumloop.com/api-reference/brain/approve-source post /brain/sources/{source_id}/approve Approve a `draft` source. It becomes `active`, the paused estimate run resumes as a real indexing run, and credits are charged. Later uploads index without another approval. # Create source Source: https://docs.gumloop.com/api-reference/brain/create-source post /brain/sources Create a file-upload source. Only `direct_file_uploads` sources can be created through the API; connected sources such as Notion or Google Drive are set up in the Gumloop app because they need an account connection. By default the source is `active` and indexes (and bills) each file as soon as it is uploaded. Set `require_approval` to `true` to create it as a `draft` instead: uploads then run a credit estimate, the source owner is notified, and nothing is indexed until [Approve source](/api-reference/brain/approve-source) is called. # Delete file Source: https://docs.gumloop.com/api-reference/brain/delete-file delete /brain/sources/{source_id}/files/{file_id} Remove a file from the source and from search. # Delete source Source: https://docs.gumloop.com/api-reference/brain/delete-source delete /brain/sources/{source_id} Delete a source, every file in it, and everything it contributed to search. This cannot be undone. # Retrieve estimate Source: https://docs.gumloop.com/api-reference/brain/get-estimate get /brain/sources/{source_id}/estimate The latest credit estimate for a source created with `require_approval`. `estimate` is `null` until the first upload has produced a run; poll until `estimate.status` is `paused_for_approval`, then call [Approve source](/api-reference/brain/approve-source). `estimated_credits` is rounded up to the nearest 5 and is an estimate, not a quote. # Retrieve source Source: https://docs.gumloop.com/api-reference/brain/get-source get /brain/sources/{source_id} Fetch one source the authenticated user can see. # List files Source: https://docs.gumloop.com/api-reference/brain/list-files get /brain/sources/{source_id}/files List the files in a file-upload source with their indexing status. Each file carries the `sha256` of its bytes, so a client can compare a local folder against the source and upload only what changed. # List sources Source: https://docs.gumloop.com/api-reference/brain/list-sources get /brain/sources List the [Company Brain](/core-concepts/brain) sources the authenticated user can see: personal sources, plus team and organization sources shared with them. Every source type is listed, including ones connected in the app such as Notion or Google Drive. # Search Company Brain Source: https://docs.gumloop.com/api-reference/brain/search post /brain/search Run a hybrid (semantic + keyword) search across the knowledge sources indexed in your [Company Brain](/core-concepts/brain) and return the most relevant, ranked snippets with citations. Results are scoped to what the authenticated user can see: personal sources, plus any team and organization sources shared with them. Requires the Brain feature, which is available on the Pro and Enterprise plans. Each search consumes Gumloop credits. # Upload files Source: https://docs.gumloop.com/api-reference/brain/upload-files post /brain/sources/{source_id}/files Upload up to 25 files as `multipart/form-data` parts named `files`. Accepted types are PDF, Word, PowerPoint, Excel, and text formats (`.txt`, `.md`, `.html`, `.csv`, `.rtf`), each up to 25 MB. Indexing starts on its own after the upload: an `active` source indexes and bills immediately, a `draft` source runs a credit estimate instead (see [Retrieve estimate](/api-reference/brain/get-estimate)). Poll [List files](/api-reference/brain/list-files) until each file's `status` is `indexed`. Files the upload policy refuses (unsupported type, too large, empty) are returned in `rejected` with a `201`; the request is a `400 no_files_accepted` only when every file was refused. # Import cookies into a browser profile Source: https://docs.gumloop.com/api-reference/browser-profiles/import-cookies post /browser-profiles/{profile_id}/cookies Add sign-in cookies to a browser profile. This is what `gumloop browser import-logins` calls. Send the cookies in Chrome extension (`chrome.cookies.Cookie`) or Chrome DevTools Protocol `Cookie` shape. With `url`, only that site's cookies are kept and the import replaces that site; without it, every site in the payload is imported. Cookies are encrypted with the profile's key before storage and are never returned by any endpoint. Use `default` as the `profile_id` to import into the owner's default profile, creating it if needed. # List browser profiles Source: https://docs.gumloop.com/api-reference/browser-profiles/list-browser-profiles get /browser-profiles List the browser profiles you own, or a team's profiles with `team_id`. A browser profile holds the sign-ins an agent's Browser ability uses. Cookie values are never returned; each profile lists its sites and cookie counts. # Create chat completion Source: https://docs.gumloop.com/api-reference/chat-completions/create-completion post /chat/completions Run one chat completion on any model Gumloop supports (Anthropic, OpenAI, Google Gemini, OpenRouter routes). The request and response use the OpenRouter chat completions schema, which extends OpenAI's. An OpenAI-style client works unchanged. OpenRouter's `reasoning`, `plugins`, `provider`, `modalities` and `image_config` fields are accepted too. Image-generation models (`gpt-image-*`, `gemini-*-image-preview`) run when `modalities` includes `"image"` and return image attachments on `choices[0].message.images`. Decision models (`typesafe/jev-*`) are not chat models. Send those to `POST /decisions`. ### Host Chat completions are served from the streaming host, `POST https://ws.gumloop.com/api/v1/chat/completions`, for both `stream: true` and `stream: false`. `api.gumloop.com` does not serve this endpoint. The Python SDK routes there automatically. With `stream: true` the response is `text/event-stream` (Server-Sent Events). Each event carries one `chat.completion.chunk` and the stream ends with `data: [DONE]`. `client.chat.completions.create(..., stream=True)` yields parsed `ChatStreamChunk` objects. ### Tool calls, images, and `tool_choice` Send messages in the OpenAI shape and Gumloop translates them for the model's provider (Anthropic, OpenAI, and Google Gemini). Models served through OpenRouter and other OpenAI-compatible providers receive the messages as sent. - **Tool-result turns**: after the model replies with `finish_reason: "tool_calls"`, append its assistant message (with `tool_calls`) and one `{"role": "tool", "tool_call_id": ..., "content": ...}` message per call, then send the conversation again. Every tool call needs a matching tool message, and every tool message must match a tool call in an earlier assistant message. - **Images**: user messages accept `image_url` content parts alongside `text` parts. The URL can be an `http(s)` URL or a base64 data URL (`data:image/png;base64,...`). Images must be JPEG, PNG, GIF, or WebP and at most 20 MB. Redirects are not followed when downloading an image. - **`tool_choice`**: `"auto"` (the default when `tools` are sent), `"none"`, `"required"`, or `{"type": "function", "function": {"name": "..."}}` to force one tool. - **`developer` messages** are treated like `system` messages. ```json { "model": "claude-sonnet-4-5", "tools": [{"type": "function", "function": {"name": "get_weather", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}}}], "messages": [ {"role": "user", "content": [ {"type": "text", "text": "What's the weather where this photo was taken?"}, {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}} ]}, {"role": "assistant", "content": null, "tool_calls": [ {"id": "call_1", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\": \"Ottawa\"}"}} ]}, {"role": "tool", "tool_call_id": "call_1", "content": "12°C and sunny"} ] } ``` A request that can't be translated returns `400 invalid_request` with `param` set to the field at fault (for example `messages[3].tool_call_id`). When the provider itself rejects the request (HTTP 400, 404, 413, or 422), the error message relays the provider's reason, prefixed with `The provider rejected the request:`. ### Billing Each completion charges the caller's credit balance based on token usage (with cache-token semantics per provider) plus a flat 30-credit fee for image-gen calls. Users who configure their own provider API key get a 50% discount. # Get evaluation config Source: https://docs.gumloop.com/api-reference/evaluations/get-config get /agents/{agent_id}/evaluation-config Retrieve the current evaluation configuration for an agent, including criteria, tags, data points, and sentiment settings. # Get evaluation metrics Source: https://docs.gumloop.com/api-reference/evaluations/get-metrics get /agents/{agent_id}/evaluations/metrics Returns aggregated grade and tag counts for an agent's evaluations over a time window. Useful for dashboards and reporting on agent quality trends. # List evaluations Source: https://docs.gumloop.com/api-reference/evaluations/list-evaluations get /agents/{agent_id}/evaluations Returns a cursor-paginated list of evaluation results for a specific agent, newest first. Only completed and failed evaluations are returned unless `status` selects another state. Each evaluation includes the grade, criteria pass/fail results, extracted data points, applied tags, and sentiment analysis. # Retrieve evaluation Source: https://docs.gumloop.com/api-reference/evaluations/retrieve-evaluation get /agents/{agent_id}/evaluations/{evaluation_id} Retrieve a single evaluation result by ID. The evaluation must belong to the specified agent. # Run evaluations Source: https://docs.gumloop.com/api-reference/evaluations/run-evaluations post /agents/{agent_id}/evaluations/run Grades up to 200 of the agent's finished sessions with its own evaluation configuration. Grading is asynchronous: each accepted session gets a result with `status: queued`; poll it with `GET /agents/{agent_id}/evaluations/{evaluation_id}` until it is `completed` or `failed`. A new result replaces the previous result for that session. Sessions are skipped, not rejected, when they are unfinished, incognito, or not owned by this agent (`ineligible`), or already have a queued or running result (`in_flight`, with the existing `result_id`). The caller is charged one credit per queued session. Set `dry_run: true` to see the cost and skips without queuing anything. Requires edit access on the agent and a plan with evaluations enabled. # Update evaluation config Source: https://docs.gumloop.com/api-reference/evaluations/update-config patch /agents/{agent_id}/evaluation-config Partially update the evaluation configuration for an agent. Omitted fields keep their current value. Provided list fields (criteria, tags, data_points) replace that list entirely. Requires Pro tier or above. # Download file Source: https://docs.gumloop.com/api-reference/file-operations/download-file post /download_file # Download multiple files Source: https://docs.gumloop.com/api-reference/file-operations/download-files post /download_files # Upload file Source: https://docs.gumloop.com/api-reference/file-operations/upload-file post /upload_file # Upload multiple files Source: https://docs.gumloop.com/api-reference/file-operations/upload-files post /upload_files # Getting started Source: https://docs.gumloop.com/api-reference/getting-started Use the Gumloop API to create agents, start chat sessions, and trigger automations programmatically. The Gumloop API is agent-first: you can create and update [agents](/api-reference/agents/create-agent), start [sessions](/api-reference/sessions/create-session) to chat with them, and use [chat completions](/api-reference/chat-completions/create-completion) from any OpenAI-compatible client. The [Python](/api-reference/sdk/python) and [JavaScript](/api-reference/sdk/javascript) SDKs wrap all of it. Webhooks, covered next, let an outside service run an agent by calling a URL — no API key, SDK, or polling loop needed. ## Agent webhooks A [webhook trigger](/core-concepts/agent_triggers#webhook-triggers) gives an agent its own URL. Anything that can send an HTTP `POST` — Stripe, GitHub, a cron job, an internal script — runs the agent by calling it. On the agent's configuration page, open the **Triggers** section, click **+ Add**, and choose **Webhook**. Give it a name and either a prompt (drop the **Raw JSON** badge where the payload should land) or turn on **Send raw JSON instead of a prompt**. Gumloop shows the URL as soon as the trigger is created, along with a `curl` example. You can copy it again any time from the trigger's detail panel. Trigger created screen showing the webhook URL and a Try it yourself curl example ```bash theme={"dark"} curl -X POST \ 'https://api.gumloop.com/trigger_incoming_webhook//' \ -H 'Content-Type: application/json' \ -d '{"customer": {"email": "ada@example.com"}}' ``` ### Request & response | | Behavior | | - | - | | **Method** | `POST` only | | **Auth** | None — the secret is part of the URL, so no API key or header is required | | **Body** | JSON (parsed even without a `Content-Type: application/json` header), form-encoded data, or raw text | | **Success** | `200` with `{"success": true}`, returned as soon as the request is accepted | | **Rejected** | `404` with `{"error": "not_found"}` for an unknown trigger, a deactivated trigger, or a wrong secret — deliberately identical, so a bad URL reveals nothing | The agent runs in the background, so the response never carries its output. Have the agent report results through a tool (Slack, email, a database write) or check the run in the agent's history. The webhook URL *is* the credential: anyone holding it can run your agent. Store it like a password, and delete the trigger to retire a URL — a new trigger always gets a fresh one. ## Finding your user ID Many API endpoints require a `user_id` parameter. You can find your User ID on the [Profile Settings page](https://www.gumloop.com/settings/profile/general), under your email address. User ID displayed on the Profile Settings page under your email address Click the copy icon next to your User ID to copy it to your clipboard. ## Authorization Agent webhooks need no credentials, but the rest of the API does. You can authenticate using one of two methods: The default method is to include your API key as a query parameter in the URL. This method is simpler and works well for most integrations: ```bash theme={"dark"} curl -X POST \ https://api.gumloop.com/api/v1/start_agent?api_key=xxxxxxxxxxxx \ -H "Content-Type: application/json" \ -d '{"user_id": "xxxxxxxxxxxxxx", "agent_id": "xxxxxxxxxxxxxx", "message": "Hello"}' ``` Alternatively, you can use the Authorization header with a Bearer token. This method is preferred when you want to keep credentials out of URLs: ```bash theme={"dark"} curl -X POST \ https://api.gumloop.com/api/v1/start_agent \ -H "Content-Type: application/json" \ -H "Authorization: Bearer xxxxxxxxxxxx" \ -d '{"user_id": "xxxxxxxxxxxxxx", "agent_id": "xxxxxxxxxxxxxx", "message": "Hello"}' ``` All examples in the API reference use the Authorization header method, but you can substitute the API key method in any of them. # Call MCP tools Source: https://docs.gumloop.com/api-reference/mcp/call-tool post /mcp/tools/call Execute a batch of 1–5 MCP tool calls. Calls run concurrently and each result reports its own `status`. When Gumloop accepts the request, MCP execution failures such as target server authentication, policy blocks, invalid tools, upstream HTTP errors, and connection failures are returned in `results[*].status` and `results[*].error`. Top-level `4xx` responses are reserved for Gumloop request, authentication, and permission failures. `200` covers homogeneous execution outcomes (all calls succeeded or all calls failed); mixed success/failure batches return `207`. If you previously treated non-2xx HTTP statuses as MCP execution failures, update your integration to inspect each result's `status` and `error`. # Get MCP server prompt Source: https://docs.gumloop.com/api-reference/mcp/get-prompt post /mcp/servers/{server_id}/prompts/get Render one prompt template with arguments and return its messages. # List MCP server prompts Source: https://docs.gumloop.com/api-reference/mcp/list-prompts get /mcp/servers/{server_id}/prompts Return the prompt templates an MCP server exposes, fetched live from the server. When the server is not `connected`, `prompts` is empty and `gumloop_auth_url` is returned. # List MCP server resources Source: https://docs.gumloop.com/api-reference/mcp/list-resources get /mcp/servers/{server_id}/resources Return the resources an MCP server exposes, fetched live from the server. When the server is not `connected`, `resources` is empty and `gumloop_auth_url` is returned so the caller can prompt the user to authenticate. # List MCP servers Source: https://docs.gumloop.com/api-reference/mcp/list-servers get /mcp/servers Return the catalog of MCP servers visible to the caller — Gumloop-hosted (`gumcp_server`), user-deployed Gumstack (`gumstack_server`), and custom (`mcp_server`) — along with each server's connection state. # List MCP server tools Source: https://docs.gumloop.com/api-reference/mcp/list-tools get /mcp/servers/{server_id}/tools Return the tools exposed by an MCP server. When the server is not in `connected` state, `tools` is empty and `gumloop_auth_url` is returned so the caller can prompt the user to authenticate. # Read MCP server resource Source: https://docs.gumloop.com/api-reference/mcp/read-resource get /mcp/servers/{server_id}/resources/read Read one resource by `uri`. Each content item is either `text` or a base64 `blob`, never both. # Retrieve an MCP server Source: https://docs.gumloop.com/api-reference/mcp/retrieve-server get /mcp/servers/{server_id} Return a single MCP server. The response populates `allowed_tool_call_ids` with the tool call IDs the caller is permitted to invoke on this server. # Create decision Source: https://docs.gumloop.com/api-reference/models/create-decision post /decisions Ask a decision model one or more typed questions about a piece of `state`. The model returns a probability for each question instead of text. The request and response use the OpenRouter Decisions schema. Jev (`typesafe/jev-1.13`) is the first decision model. Any model with `is_classifier_model: true` in `GET /models` works here. Chat models are refused with `model_unavailable`. Send those to `POST /chat/completions`. You choose the question ids. The answers come back under the same ids. There are three question types: - `noul` is a yes/no question. The answer is `noul`, the probability of yes. `criteria.true` and `criteria.false` are optional descriptions of each side. - `choice` picks one option from `criteria`, a map of option id to description. A description may be `null`. The answer is `choice`, `probabilities` over every option, and `confidence`. - `score` places the state on the ordered rubric in `criteria`, a list with the lowest level first. The answer is `score` (the weighted position), `probabilities` per level, `legend`, and `confidence`. `state`, `instructions` and criteria accept a string, a JSON object, or an array. The response `model` is the exact version the provider served, for example `typesafe/jev-1.13-20260917`. Billing uses the model you requested. There is no streaming form. The server applies its zero-data-retention provider policy after any `provider` preferences you send. ### Billing Each call charges the caller's credit balance from the provider-reported cost, or from the model's token rate when the provider reports none. A call costs at least one credit, so put every independent question about one piece of state in a single request. # List models Source: https://docs.gumloop.com/api-reference/models/list-models get /models List the LLMs and preset model chains available to the caller, grouped for display in a model picker. # Route a message to a model Source: https://docs.gumloop.com/api-reference/models/route-model post /models/route Ask Gumloop Chew — the model router behind **Auto** — which model it would use for a given message, and why. Chew is a router, not a model: `router` is always `gumloop-chew`, and the concrete model it selected is `route.model`. This endpoint returns a decision only. It does not run the selected model or its fallbacks. The routing judgement consumes credits and is bounded by the caller's model access. Omit `models` to use the deduplicated union of Chew's lane chains, not every model the caller may use. Restricted candidates can appear with `status: "restricted"`; they are never selected or included in `fallback_models`. Team scope requires actual team membership, even within the same organization. Personal API keys and OAuth are supported; this is not team-key-only. # OAuth 2.0 Source: https://docs.gumloop.com/api-reference/oauth Gumloop supports OAuth 2.0, which is recommended if you're building an application that other Gumloop users sign in to. The flow follows the standard **authorization code grant with PKCE (S256)** and issues refresh tokens. ## Register an OAuth application OAuth client registration is currently invite-only. Email **[support@gumloop.com](mailto:support@gumloop.com)** with your app name, use case, redirect URI(s), and logo. We'll review and reach out with a `client_id`. ## Redirect the user to Gumloop When authorizing a user, redirect to the authorization endpoint with the correct parameters and scopes. ```http theme={"dark"} GET https://api.gumloop.com/oauth/authorize ``` | Parameter | Description | | - | - | | `client_id` | (required) Client ID from your registered OAuth app | | `redirect_uri` | (required) One of your app's registered redirect URIs | | `response_type=code` | (required) Only `code` is supported | | `scope` | (required) Space-separated list of [scopes](#scopes) | | `code_challenge` | (required) Your PKCE code challenge | | `code_challenge_method=S256` | (required) Only `S256` is supported | | `state` | (optional, recommended) Opaque value echoed back on redirect to prevent CSRF | ### Example ```http theme={"dark"} GET https://api.gumloop.com/oauth/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=https%3A%2F%2Fyourapp.com%2Foauth%2Fcallback &scope=gumloop_api &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM &code_challenge_method=S256 &state=SECURE_RANDOM ``` ## Handle the redirect After the user approves your app, Gumloop redirects them back to your `redirect_uri` with the authorization `code` and your `state` in the query string. Always validate that `state` matches the value you sent. ```http theme={"dark"} GET https://yourapp.com/oauth/callback?code=9a5190f637d8...&state=SECURE_RANDOM ``` ## Exchange the code for tokens Exchange the `code` (plus your PKCE `code_verifier`) for an access token. ```http theme={"dark"} POST https://api.gumloop.com/oauth/token Content-Type: application/x-www-form-urlencoded ``` | Parameter | Description | | - | - | | `grant_type=authorization_code` | (required) | | `code` | (required) Authorization code from the previous step | | `redirect_uri` | (required) Same value sent in the authorize request | | `client_id` | (required) Your client ID | | `code_verifier` | (required) The PKCE verifier matching the challenge sent in the authorize request | ### Example ```bash theme={"dark"} curl -X POST https://api.gumloop.com/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=9a5190f637d8..." \ -d "redirect_uri=https://yourapp.com/oauth/callback" \ -d "client_id=YOUR_CLIENT_ID" \ -d "code_verifier=YOUR_CODE_VERIFIER" ``` ### Response ```json theme={"dark"} { "access_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "gumloop_api", "refresh_token": "..." } ``` ## Make API requests Pass the access token as a bearer header on every request, exactly like an API key: ```bash theme={"dark"} curl https://api.gumloop.com/api/v1/agents \ -H "Authorization: Bearer ACCESS_TOKEN" ``` ## Refresh an access token When `expires_in` elapses, exchange the refresh token for a new access token. ```http theme={"dark"} POST https://api.gumloop.com/oauth/token Content-Type: application/x-www-form-urlencoded ``` | Parameter | Description | | - | - | | `grant_type=refresh_token` | (required) | | `refresh_token` | (required) Refresh token from the previous response | | `client_id` | (required) Your client ID | ## Revoke a token ```http theme={"dark"} POST https://api.gumloop.com/oauth/revoke Content-Type: application/x-www-form-urlencoded ``` | Parameter | Description | | - | - | | `token` | (required) The access or refresh token to revoke | | `client_id` | (required) Your client ID | ## Scopes | Scope | Grants | | - | - | | `gumloop_api` | Call the Gumloop developer API on behalf of the user | | `userinfo` | Read the user's basic profile (email, name) | The `gumloop_api` scope requires the authorizing user to be on the [Pro plan or above](https://www.gumloop.com/pricing). Token exchange will fail if the user's account does not meet this requirement. # Create evaluation Source: https://docs.gumloop.com/api-reference/organization-evaluations/create-evaluation post /evaluations Creates an organization evaluation. A new evaluation has no targets, so it cannot start enabled: set targets with `PUT /evaluations/{evaluation_id}/targets`, then enable it with `PATCH /evaluations/{evaluation_id}`. Rubric values are validated strictly: an unknown `frequency`, criterion `priority`, `type`, data point `data_type`, or session type, a criterion without `name` and `prompt`, or a duplicate tag name returns `400 invalid_request` with the offending paths in `error.details.fields`. # Delete evaluation Source: https://docs.gumloop.com/api-reference/organization-evaluations/delete-evaluation delete /evaluations/{evaluation_id} Deletes the evaluation. It stops running and disappears from lists; results it already produced stay attached to their sessions. # Get evaluation metrics Source: https://docs.gumloop.com/api-reference/organization-evaluations/get-metrics get /evaluations/{evaluation_id}/metrics Grade counts for one evaluation over a trailing window (default 30 days, 1–365). # Get evaluation options Source: https://docs.gumloop.com/api-reference/organization-evaluations/get-options get /evaluation-options Allowed values for evaluation fields and filters — session types, criterion types and priorities, data point types, frequencies, grades, statuses, target types, skip reasons — plus size limits. Use these instead of hardcoding enums. # List evaluations Source: https://docs.gumloop.com/api-reference/organization-evaluations/list-evaluations get /evaluations Cursor-paginated list of an organization's evaluations with their targets, coverage, and result rollups. Requires the `organization:manage_evaluations` permission (Enterprise plan). # List evaluation results Source: https://docs.gumloop.com/api-reference/organization-evaluations/list-results get /evaluations/{evaluation_id}/results Cursor-paginated results for one evaluation across every agent it grades, newest first. Each session appears once with its latest result; queued and in-progress results are included so a run can be followed to completion. # Retrieve evaluation Source: https://docs.gumloop.com/api-reference/organization-evaluations/retrieve-evaluation get /evaluations/{evaluation_id} Returns one evaluation with its rubric, targets, current coverage, and result rollup. # Retrieve evaluation result Source: https://docs.gumloop.com/api-reference/organization-evaluations/retrieve-result get /evaluations/{evaluation_id}/results/{result_id} One result, including per-criterion outcomes, extracted data points, and applied tags. Poll this after `POST /evaluations/{evaluation_id}/run` until `status` is `completed` or `failed`. # Run evaluation on sessions Source: https://docs.gumloop.com/api-reference/organization-evaluations/run-evaluation post /evaluations/{evaluation_id}/run Grades up to 200 existing sessions with this evaluation. Grading is asynchronous: each accepted session gets a result with `status: queued`; poll it with `GET /evaluations/{evaluation_id}/results/{result_id}` until it is `completed` or `failed`. Sessions are skipped, not rejected, when they are not completed sessions of an agent the evaluation covers (`ineligible`) or already have a queued or running result for this evaluation (`in_flight`, with the existing `result_id`). The caller is charged one credit per queued session. Set `dry_run: true` to see the cost and skips without queuing anything. # Set evaluation targets Source: https://docs.gumloop.com/api-reference/organization-evaluations/set-targets put /evaluations/{evaluation_id}/targets Replaces the full set of targets — who the evaluation grades. Targets expand to agents live: `organization` covers every agent in the organization, `team` every agent a team owns, `user` a member's personal agents, `agent` one agent. Removing the last target pauses an enabled evaluation; `enabled` in the response reflects that. # Update evaluation Source: https://docs.gumloop.com/api-reference/organization-evaluations/update-evaluation patch /evaluations/{evaluation_id} Partial update. Only the fields you send change. `config` is merged field by field; a list you send (`criteria`, `tags`, `data_points`) replaces that list wholesale. `description: null` clears the description. Setting `enabled: true` requires at least one criterion, tag, or data point (`400 organization_evaluation_empty_rubric`) and at least one covered agent (`400 organization_evaluation_no_targets`). Emptying the rubric of an enabled evaluation pauses it. # Export data Source: https://docs.gumloop.com/api-reference/organization/export-data post /export_data This endpoint allows enterprise organization administrators to create and initiate a comprehensive data export for their organization or specific workspaces. The export supports six data types: - **Workflow data** (`data_type: "workflows"`): Includes workflow runs, workbook details, user information, and other organizational data. - **Agent data** (`data_type: "agents"`): Includes agent configurations, metadata, tools, and creator information. - **Agent interaction data** (`data_type: "agent_interactions"`): Includes agent interaction data with timestamps, credit costs, trigger types, and message counts. - **Credit log data** (`data_type: "credit_logs"`): Includes credit transaction history with charges, balances, categories, and user attribution. - **Interaction evaluation data** (`data_type: "interaction_evaluations"`): Includes one row per completed [evaluation](/core-concepts/evaluations) of a chat, with its grade, call outcome, sentiment, and the model that graded it. - **Gumstack data** (`data_type: "gumstack"`): Includes Gumstack MCP tool call activity with timestamps, statuses, and latency. The available `export_fields` depend on the selected `data_type`. See the field descriptions below for details. **Scoping requirement:** For non-credit-log exports, at least one scoping parameter must be provided: `workspace_ids`, `include_all_workspaces`, `include_personal_workspaces`, or `entity_ids`. Requests that omit all scoping parameters will receive a `400` error. **Note:** Credit log exports work differently from workflow and agent exports. When `data_type` is `"credit_logs"`, the following parameters are **not applicable** and will be ignored: `export_level`, `workspace_ids`, `include_all_workspaces`, `include_personal_workspaces`, and `entity_ids`. Credit log exports are always scoped to the entire organization. Use `category_filter` to filter by credit log category. # Get data export status Source: https://docs.gumloop.com/api-reference/organization/export-status get /export_status This endpoint retrieves the status of a data export job and optionally downloads the export file (as CSV) if the export has completed successfully. Use the `data_export_id` returned by the [Export data](/api-reference/organization/export-data) endpoint to check progress. # Retrieve audit logs Source: https://docs.gumloop.com/api-reference/organization/get-audit-logs get /get_audit_logs This endpoint retrieves audit logs for all users in an organization for a specified time period. # Get custom role credit limit Source: https://docs.gumloop.com/api-reference/organization/get-role-credit-limit get /organizations/{organization_id}/roles/{role_id}/credit-limit This endpoint returns the monthly credit limit of one custom role. A `monthly_credit_limit` of `null` means the role sets no limit of its own. # List organizations Source: https://docs.gumloop.com/api-reference/organization/list-organizations get /organizations Returns the organization the authenticated user belongs to. Use its `id` as `organization_id` on the evaluation endpoints. # List custom role credit limits Source: https://docs.gumloop.com/api-reference/organization/list-role-credit-limits get /organizations/{organization_id}/roles/credit-limits This endpoint lists every active custom role in an organization together with its monthly credit limit, so external systems can manage credit limits programmatically. A `monthly_credit_limit` of `null` means the role sets no limit of its own. The limit applies to each member of the role individually; when a user belongs to multiple roles, the highest limit across their roles wins. # Manage custom role users Source: https://docs.gumloop.com/api-reference/organization/manage-permission-group-users post /manage_permission_group_users This endpoint allows organization administrators to add or remove users from a custom role (formerly "permission group"). Adding a user to a role does not remove them from any other role they belong to. # Manage workspace users Source: https://docs.gumloop.com/api-reference/organization/manage-workspace-users post /manage_workspace_users This endpoint allows organization administrators to add or remove users from a workspace. # Set custom role credit limit Source: https://docs.gumloop.com/api-reference/organization/set-role-credit-limit put /organizations/{organization_id}/roles/{role_id}/credit-limit This endpoint sets or clears the monthly credit limit of a custom role. The limit applies to each member of the role individually and takes effect immediately: member allowances are recalculated while preserving credits already used in the current billing cycle. Send `"monthly_credit_limit": null` to clear the role-level limit so members revert to the organization default. When a user belongs to multiple roles, the highest limit across their roles wins. Requests that do not change the stored value are no-ops. Changes are recorded in the organization audit trail. # JavaScript SDK Source: https://docs.gumloop.com/api-reference/sdk/javascript For convenience, we have created a Gumloop JavaScript SDK to more easily perform operations like starting an automation and retrieving outputs. ## Installation ```bash theme={"dark"} npm install gumloop ``` ## Usage ```typescript theme={"dark"} import { GumloopClient } from "gumloop"; // Initialize the client const client = new GumloopClient({ apiKey: "your_api_key", userId: "your_user_id", }); // Run a flow and wait for outputs async function runFlow() { try { const output = await client.runFlow("your_flow_id", { recipient: "example@email.com", subject: "Hello", body: "World", }); console.log(output); } catch (error) { console.error("Flow execution failed:", error); } } runFlow(); ``` Optionally add a `project_id` when creating the client if running automations in a workspace: ```typescript theme={"dark"} const client = new GumloopClient({ apiKey: "your_api_key", userId: "your_user_id", projectId: "your_project_id" }); ``` # Python SDK Source: https://docs.gumloop.com/api-reference/sdk/python The Gumloop Python SDK ships two clients: * **`Gumloop`** — the modern resource client used for chat completions, agents, sessions, MCP, skills, artifacts, and teams. * **`GumloopClient`** — the legacy flows client used to start saved automations and poll for outputs. Emits a `DeprecationWarning` at construction. Pick `Gumloop` for new code. Use `GumloopClient` only if you need `run_flow` against an existing saved automation. ## Installation ```bash theme={"dark"} uv add gumloop ``` ## Chat completions `client.chat.completions.create(...)` is an OpenAI-compatible chat surface that routes to every model Gumloop supports (Anthropic, OpenAI, Google Gemini, OpenRouter routes). The streaming variant returns an iterator of `ChatStreamChunk`; the unary variant returns a `ChatResult`. `model` must be a concrete model. `gumloop-chew` — the [**Auto** router](/core-concepts/ai_models#auto-faq) — picks a model instead of being one. Use `client.models.route(...)` (or `POST /models/route`) to get the model it would choose, then pass that here. Requires a current `gumloop` package that includes the models resource. ```python theme={"dark"} from gumloop import Gumloop client = Gumloop(access_token="your_access_token") result = client.chat.completions.create( model="claude-sonnet-4-5", messages=[{"role": "user", "content": "Capital of Canada?"}], ) print(result.choices[0].message.content) ``` ### Streaming ```python theme={"dark"} for chunk in client.chat.completions.create( model="claude-sonnet-4-5", messages=[{"role": "user", "content": "Write a haiku about Toronto."}], stream=True, ): delta = chunk.choices[0].delta if delta.content: print(delta.content, end="", flush=True) ``` ### Structured output Pass `response_format={"type": "json_schema", "json_schema": {...}}` to constrain the response to a JSON Schema. The SDK accepts the same shape the OpenAI API documents. ```python theme={"dark"} result = client.chat.completions.create( model="claude-sonnet-4-5", messages=[{"role": "user", "content": "Return JSON with the capital of Canada."}], response_format={ "type": "json_schema", "json_schema": { "name": "answer", "strict": True, "schema": { "type": "object", "properties": {"capital": {"type": "string"}}, "required": ["capital"], "additionalProperties": False, }, }, }, ) print(result.choices[0].message.content) # '{"capital":"Ottawa"}' ``` ### Image generation Request an image-generation model such as `gpt-image-2.5-flare` or `gemini-*-image-preview` with `modalities=["image", "text"]`. The response carries image attachments on `choices[0].message.images` as data URLs. Streaming variants emit partial frames natively for OpenAI gpt-image models. ```python theme={"dark"} result = client.chat.completions.create( model="gpt-image-2.5-flare", messages=[{"role": "user", "content": "A red maple leaf on white"}], modalities=["image", "text"], image_config={"size": "1024x1024"}, ) for image in result.choices[0].message.images: print(image.image_url.url[:64], "...") ``` ### Tool calling Pass OpenAI-shape tool definitions; the SDK forwards them unchanged so any LLM that supports function calling can invoke them. ```python theme={"dark"} result = client.chat.completions.create( model="claude-sonnet-4-5", messages=[{"role": "user", "content": "What's the weather in Toronto?"}], tools=[{ "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }, }], ) for tc in result.choices[0].message.tool_calls or []: print(tc.function.name, tc.function.arguments) ``` ### Bring your own provider key When the calling user has configured their own provider API key (OpenAI, Anthropic, etc.) in Gumloop, billing follows that account's pricing policy. Usage pricing can waive inference for BYOK; some legacy organizations use a partial discount. See [Credits](/core-concepts/credits). No SDK change is required. ## MCP tools `client.mcp.execute(...)` returns an `McpExecuteResponse` with one result per tool call. MCP execution failures, such as target server authentication errors or upstream connection failures, are reported on each result instead of being raised as `APIStatusError`. Gumloop request errors, such as missing credentials, invalid request bodies, or endpoint permission failures, can still raise `APIStatusError`. ```python theme={"dark"} from gumloop import APIStatusError, Gumloop client = Gumloop(access_token="your_access_token") try: response = client.mcp.execute( server_id="gumloop_slack", tool_name="slack_send_message", arguments={"channel": "#general", "text": "Hello from Gumloop"}, ) except APIStatusError as error: print(f"Gumloop API request failed: {error}") raise result = response.results[0] if result.status != "success": print(result.error) else: print(result.decoded_content) ``` `decoded_content` is a Python SDK convenience property. Raw REST responses include the underlying `content` array. ## Agent versions Every agent keeps an immutable history of its configuration. `client.agents.list_versions(...)` pages through those snapshots newest-first, and `client.agents.get_version(...)` returns one version's full configuration plus the structured diff against the version before it. ```python theme={"dark"} from gumloop import Gumloop client = Gumloop(access_token="your_access_token") response = client.agents.list_versions("abc123DEFghiJKL", page_size=20) for version in response.versions: print(version.id, version.major_version, version.is_deployed, version.created_at) detail = client.agents.get_version("abc123DEFghiJKL", response.versions[0].id) print(detail.version.composition.model_name) print(detail.version.composition.system_prompt) print(detail.changes) # None for the agent's first version ``` Both calls require configuration access on the agent, and they are read-only — deploying or restoring a version has to happen in the app. ## Evaluations `client.agents.list_evaluations(...)` pages through an agent's graded chats newest-first, `client.agents.get_evaluation_metrics(...)` returns grade and tag counts over a window, and `client.agents.run_evaluations(...)` queues evaluations for finished sessions. `client.agents.get_evaluation_options()` lists the criterion types, priorities, and limits the config accepts. ```python theme={"dark"} from datetime import datetime, timedelta, timezone from gumloop import Gumloop client = Gumloop(access_token="your_access_token") since = datetime.now(timezone.utc) - timedelta(days=7) failed = client.agents.list_evaluations("abc123DEFghiJKL", grade="needs_attention", created_after=since) for evaluation in failed.evaluations: print(evaluation.interaction_id, evaluation.summary) metrics = client.agents.get_evaluation_metrics("abc123DEFghiJKL", days=30) print(metrics.grades) run = client.agents.run_evaluations("abc123DEFghiJKL", session_ids=[e.interaction_id for e in failed.evaluations]) for queued in run.results: print(queued.session_id, queued.id) for skipped in run.skipped: print(skipped.session_id, skipped.reason) ``` Listing and metrics need read access on the agent and cover the chats you can see. Running evaluations needs edit access and consumes one credit per session; pass `dry_run=True` to see the cost and the sessions that would be skipped (unfinished, or already queued) without queuing anything. Results from an organization evaluation enforced on the agent are listed with `list_evaluations(agent_id, organization_evaluation_id=...)`. ## Organization evaluations `client.evaluations` manages rubrics an organization admin defines once and applies to teams, people, or individual agents (Enterprise plan, **Manage evaluations** permission). A new evaluation starts disabled: set its targets, then enable it. Run it over past sessions with `run(...)`; grading is asynchronous, so poll each returned result id. ```python theme={"dark"} import time from gumloop import Gumloop client = Gumloop(access_token="your_access_token") organization_id = client.organizations.list().organizations[0].id created = client.evaluations.create( organization_id=organization_id, name="Support tone", config={ "criteria": [ {"name": "Greets the customer", "prompt": "Did the agent greet the customer by name?", "priority": "needs_review"} ] }, ) evaluation_id = created.evaluation.id client.evaluations.set_targets(evaluation_id, [{"type": "team", "id": "team_abc"}]) client.evaluations.update(evaluation_id, enabled=True) queued = client.evaluations.run(evaluation_id, ["session_1", "session_2"]) for result in queued.results: polled = client.evaluations.get_result(evaluation_id, result.id).result while polled.status in ("queued", "in_progress"): time.sleep(5) polled = client.evaluations.get_result(evaluation_id, result.id).result print(result.session_id, polled.status, polled.grade) for result in client.evaluations.list_results(evaluation_id, grade="needs_attention").results: print(result.agent_id, result.session_id, result.summary) ``` `client.evaluations.options()` returns the allowed values for every enum field (grades, statuses, target types, session types, criterion priorities) and the size limits. ## Company Brain `client.brain.search(...)` runs a hybrid (semantic + keyword) search across the knowledge sources indexed in your [Company Brain](/core-concepts/brain) and returns ranked results scoped to what you can access. Brain is available on the Pro and Enterprise plans, and each search consumes credits. ```python theme={"dark"} from gumloop import Gumloop client = Gumloop(access_token="your_access_token") response = client.brain.search( "what is our refund policy?", limit=8, # optional, 1–50 (default 8) source_type=["notion", "google_drive"], # optional filter ) for result in response.results: print(result.score, result.source, result.title, result.url) ``` Each result carries `document_id`, `source`, `title`, `content`, `url`, `score`, `updated_at`, `owner_name`, `owner_email`, `parent_title`, and `metadata`. Omit `source_type` to search every source you can access; valid values are `notion`, `google_drive`, `slack`, `github`, `confluence`, `direct_file_uploads`, and `gumloop_artifacts`. ### Sources and files Create file-upload sources and put files into them. Only `direct_file_uploads` sources can be created through the SDK; connected sources are set up in the app. ```python theme={"dark"} source = client.brain.create_source("Engineering docs").source # personal, active # client.brain.create_source("Runbooks", scope="team", team_id="...") # client.brain.create_source("Policies", scope="organization", require_approval=True) upload = client.brain.upload_files(source.id, {"handbook.pdf": open("handbook.pdf", "rb").read()}) print([f.status for f in upload.files], upload.rejected) # indexing starts on its own for f in client.brain.list_files(source.id).files: print(f.file_name, f.status, f.sha256) # uploaded → indexing → indexed client.brain.delete_file(source.id, upload.files[0].id) client.brain.delete_source(source.id) ``` `list_sources(scope=..., source_type=..., team_id=..., page_size=..., cursor=...)` and `get_source(id)` read sources of every type. A source created with `require_approval=True` is a draft: `get_estimate(id).estimate.estimated_credits` shows the cost once `estimate.status` is `paused_for_approval`, and `approve_source(id)` starts indexing. Every file's `sha256` lets you diff a local folder against a source; the CLI's [`gumloop brain sync`](/cli/brain) does exactly that. ## Flows (legacy client) ```python theme={"dark"} from gumloop import GumloopClient # Initialize the client client = GumloopClient( api_key="your_api_key", user_id="your_user_id" ) # Run a flow and wait for outputs output = client.run_flow( flow_id="your_flow_id", inputs={ "recipient": "example@email.com", "subject": "Hello", "body": "World" } ) print(output) ``` Optionally add a `project_id` when creating the client if running automations in a workspace: ```python theme={"dark"} from gumloop import GumloopClient # Initialize the client client = GumloopClient( api_key="your_api_key", user_id="your_user_id", project_id="your_project_id" ) ``` # Cancel session Source: https://docs.gumloop.com/api-reference/sessions/cancel-session post /sessions/{session_id}/cancel Cancel an in-progress session. If the session is currently `processing` or `queued`, any running stream is aborted and the session is transitioned to `failed`. If the session is already `completed` or `failed`, its current state is returned unchanged. The response carries a `session` envelope but only `id`, `agent_id`, and `state` are populated. # Create session Source: https://docs.gumloop.com/api-reference/sessions/create-session post /agents/{agent_id}/sessions Create a new session for an agent. When `input` is provided, the message is enqueued and the agent begins processing — the response returns `202` with the session in `processing` or `queued` state. When `input` is omitted, an idle session stub is created and the response returns `201`. `agent_id` also accepts the reserved aliases `gumball` and `analytics`, which resolve to your personal Gumball and analytics agents (created on first use). ### Streaming the response `api.gumloop.com` only serves the non-streaming response above. To stream agent output as it's produced, send the same request body (with `stream: true`) to the streaming host instead: `POST https://ws.gumloop.com/api/v1/agents/{agent_id}/sessions` The response is `text/event-stream` (Server-Sent Events). With the Python SDK, `client.sessions.stream(agent_id, input="...")` routes to `ws.gumloop.com` automatically and yields parsed `StreamEvent` objects. If you send `stream: true` to `api.gumloop.com` by mistake, the response is a `400` whose body contains the correct streaming host so you can retry against it. # Delete queued message Source: https://docs.gumloop.com/api-reference/sessions/delete-queued-message delete /sessions/{session_id}/queue/{queued_message_id} Remove a message from the session's queue before it is sent. # List queued messages Source: https://docs.gumloop.com/api-reference/sessions/list-queued-messages get /sessions/{session_id}/queue List the messages waiting in a session's queue, in the order they will be sent. Queued messages are drained automatically when the agent finishes its current turn. # List sessions Source: https://docs.gumloop.com/api-reference/sessions/list-sessions get /agents/{agent_id}/sessions List sessions for an agent with cursor-based pagination, optional filtering, and search. # Queue message Source: https://docs.gumloop.com/api-reference/sessions/queue-message post /sessions/{session_id}/queue Add a message to a session's queue instead of interrupting the agent. Queued messages are sent automatically, in order, when the agent finishes its current turn. A session's queue holds at most 20 messages. To interrupt the current turn and send a queued message immediately, use [Send queued message now](/api-reference/sessions/send-queued-message). # Rename session Source: https://docs.gumloop.com/api-reference/sessions/rename-session patch /sessions/{session_id} Rename a session. `name` is the only mutable field; it is trimmed and must be between 1 and 256 characters after trimming. Returns the full session, in the same shape as Retrieve session. # Resolve approvals Source: https://docs.gumloop.com/api-reference/sessions/resolve-approvals post /sessions/{session_id}/approvals Answer pending asks on a session that is paused in the `approval_required` state — tool approvals, human input requests, and checkpoints. List the pending asks with Retrieve session: each entry in `pending_approvals` carries the `action_request_id` to answer, and `human_input` asks include the `questions` to fill in via `response.values`. Resolutions are processed in order; the agent resumes once the pending asks are answered. # Retrieve session Source: https://docs.gumloop.com/api-reference/sessions/retrieve-session get /sessions/{session_id} Retrieve a session by ID, including its messages, current state, agent metadata, and participants. # Send message Source: https://docs.gumloop.com/api-reference/sessions/send-message post /sessions/{session_id}/messages Append a user message to an existing session and resume the agent. The session must be `idle`, `completed`, `failed`, or `approval_required`; sending to a session that is `processing` or `queued` returns `409 interaction_not_in_terminal_state`. To hand the agent a message while it is still busy, use the [message queue](/api-reference/sessions/queue-message) instead. Files uploaded via [Upload session file](/api-reference/sessions/upload-session-file) can be attached to the message with `attachments`. ### Sessions waiting on an approval A session that stopped to ask you something is `approval_required`, and you have two ways to move it forward: - **Answer the ask.** Send the pending asks' responses to [Resolve approvals](/api-reference/sessions/resolve-approvals). Use this to approve or reject a tool call, or to answer an Ask Question the agent raised. This endpoint rejects `approval_responses` with a `400`. - **Send a follow-up instead.** Post a normal message here. It is appended to the session transcript and starts a new turn, leaving the pending ask unanswered. Use this when the answer no longer matters — for example to redirect the agent or drop the request it was asking about. See [Human in the Loop](/core-concepts/human_in_the_loop) for how agents pause for approvals and questions. ### Streaming the response `api.gumloop.com` only serves the non-streaming response above. To stream agent output as it's produced, send the same request body (with `stream: true`) to the streaming host instead: `POST https://ws.gumloop.com/api/v1/sessions/{session_id}/messages` The response is `text/event-stream` (Server-Sent Events). With the Python SDK, `client.sessions.stream_message(session_id, input="...")` routes to `ws.gumloop.com` automatically and yields parsed `StreamEvent` objects. If you send `stream: true` to `api.gumloop.com` by mistake, the response is a `400` whose body contains the correct streaming host so you can retry against it. # Send queued message now Source: https://docs.gumloop.com/api-reference/sessions/send-queued-message post /sessions/{session_id}/queue/{queued_message_id}/send Send a queued message immediately instead of waiting for the agent to finish its current turn. Any in-progress run is aborted, the queued message is appended to the transcript, and the agent starts processing it. The response is the same envelope as Send message. Queued messages cannot be sent this way on incognito sessions, and a message that is currently being edited must have its edit finished or cancelled first. # Update queued message Source: https://docs.gumloop.com/api-reference/sessions/update-queued-message patch /sessions/{session_id}/queue/{queued_message_id} Replace the content of a message that is still waiting in the session's queue. # Upload session file Source: https://docs.gumloop.com/api-reference/sessions/upload-session-file post /sessions/{session_id}/files Upload a file into a session's input namespace so it can be attached to a message. The response returns the stored path — pass it as `file_name` in the `attachments` array when sending a message on the same session. Files are base64 encoded in the request body and limited to 200MB (decoded). Uploaded files are scoped to the session they were uploaded to and cannot be attached to messages on other sessions. # Create skill Source: https://docs.gumloop.com/api-reference/skills/create-skill post /skills Upload a skill package and create a new skill. The package must include a `SKILL.md` with `name` and `description` frontmatter; uploads may be a single `.md` file (stored as `SKILL.md`), or a `.zip` / `.skill` archive containing `SKILL.md` at its root. The initial version is created automatically. Maximum upload size is 10 MB. # Delete skill Source: https://docs.gumloop.com/api-reference/skills/delete-skill delete /skills/{skill_id} Permanently delete a skill. This is a soft-delete — the skill will no longer appear in listings or be usable by agents. # Download skill Source: https://docs.gumloop.com/api-reference/skills/download-skill get /skills/{skill_id}/download Generate a signed URL to download a skill's contents as a `.skill` archive (ZIP). When `version_id` is provided, returns that exact version; otherwise returns the current draft. # List skills Source: https://docs.gumloop.com/api-reference/skills/list-skills get /skills List skills the caller has access to. Filter by team, search by name, or narrow to a specific creator, related MCP server, or agent. # Update skill Source: https://docs.gumloop.com/api-reference/skills/update-skill patch /skills/{skill_id} Replace a skill's files with a new upload. Reparses `SKILL.md` to update the skill's `name`, `description`, and `metadata`, and creates a new version. Maximum upload size is 10 MB. # List teams Source: https://docs.gumloop.com/api-reference/teams/list-teams get /teams List teams the authenticated caller belongs to. # Agents Source: https://docs.gumloop.com/cli/agents List, inspect, create, and update agents from the terminal. `gumloop agents` lets you list, inspect, create, and update your [agents](/core-concepts/agents) without leaving the terminal. Every command accepts `--json` to print the raw response payload. ## List agents ```bash theme={"dark"} gumloop agents list gumloop agents list --search support --limit 50 ``` Returns a tab-separated table with `ID`, `NAME`, `MODEL`, `TEAM`, and `ACTIVE`. If the response is paginated, the next cursor is printed at the bottom — pass it back with `--cursor`. | Flag | Description | | - | - | | `--search` | Filter agents by name or description. | | `--limit` | Maximum number of agents to return. | | `--cursor` | Pagination cursor from a previous list call. | | `--json` | Print the raw response payload. | The `--team-id` global flag scopes the listing to a single team. ## Get an agent ```bash theme={"dark"} gumloop agents get agent_abc ``` Prints the agent's name as a header followed by `id`, `model_name`, `team_id`, `is_active`, `folder_id`, `description`, `created_at`, and the system prompt (if set). Grab the agent ID from the first column of `gumloop agents list`. ## List agent versions ```bash theme={"dark"} gumloop agents versions agent_abc gumloop agents versions agent_abc --limit 50 --json ``` Returns a tab-separated table with `ID`, `VERSION`, `NAME`, `DEPLOYED`, and `CREATED`, newest first. If the response is paginated, the next cursor is printed at the bottom — pass it back with `--cursor`. | Flag | Description | | - | - | | `--limit` | Maximum number of versions to return. | | `--cursor` | Pagination cursor from a previous versions call. | | `--json` | Print the raw response payload. | Versions are read-only snapshots of the agent's configuration; the CLI cannot deploy or restore one. ## Export an agent version ```bash theme={"dark"} gumloop agents export agent_abc gv_a1b2c3d4 gumloop agents export agent_abc gv_a1b2c3d4 --output agent-version.json ``` Writes one version as JSON: the version's full configuration (`composition`) plus the structured `changes` against the version before it. `changes` is `null` for an agent's first version. | Flag | Description | | - | - | | `-o`, `--output` | File to write. Omit or pass `-` to print to stdout. | Grab the version ID from the first column of `gumloop agents versions `. ## Create an agent ```bash theme={"dark"} gumloop agents create --name "Support bot" --model gumloop-chew ``` | Flag | Required | Description | | - | - | - | | `--name` | yes | Display name for the new agent. | | `--model` | | Model name (for example `gumloop-chew`, `anthropic/claude-sonnet-4`). Omit to use the server default for the account, which is not always Auto. | | `--description` | | Short description. | | `--system-prompt` | | Inline system prompt text. | | `--system-prompt-file` | | Path to a file containing the system prompt. Mutually exclusive with `--system-prompt`. | | `--tools-json` | | Inline JSON array of tool config objects. | | `--tools-file` | | Path to a JSON file containing the tools array. Mutually exclusive with `--tools-json`. | | `--json` | | Print the raw response payload. | `gumloop-chew` is [Gumloop Chew](/core-concepts/ai_models#auto-faq), the router that picks a model per message rather than a model of its own. The CLI does not treat `auto` as an alias. Pass the system prompt from a file: ```bash theme={"dark"} gumloop agents create --name "Sales research" --model gumloop-chew \ --system-prompt-file ./prompts/sales.md ``` Attach tools (each entry in the array is one tool config; the shape varies by type): ```bash theme={"dark"} gumloop agents create --name "Email reader" --model gumloop-chew \ --tools-json '[{"type":"gumcp_server","server":"gmail"}]' ``` To see the exact tool config shape an agent uses, run `gumloop agents get --json` on an existing agent and copy the `tools` array out of the response. ## Update an agent ```bash theme={"dark"} gumloop agents update agent_abc --name "Better bot" gumloop agents update agent_abc --system-prompt-file new-prompt.md ``` Only the flags you pass are changed; everything else is left untouched. The flag surface matches `agents create` and adds: | Flag | Description | | - | - | | `--is-active` / `--inactive` | Set the agent's active state. `--inactive` retires the agent — see the warning below. | `--inactive` (and `is_active: false` on the API) is **not** a pause switch. It retires the agent: it stops appearing in `gumloop agents list`, and `gumloop agents get`/`update` return a `404` afterwards, so you cannot turn it back on yourself. Contact [support@gumloop.com](mailto:support@gumloop.com) if you need a retired agent restored. To stop an agent from running on its own while keeping it fully reachable, deactivate its triggers instead — open the agent's **Triggers** section in the app and use the three-dot menu on each trigger, or ask the agent to pause the schedule in chat. See [Managing active triggers](/core-concepts/agent_triggers#managing-active-triggers). ## Evaluations ```bash theme={"dark"} gumloop agents eval-options gumloop agents eval-metrics agent_abc --days 30 gumloop agents eval-run agent_abc --session-id session_1 --session-id session_2 gumloop agents eval-run agent_abc --session-id session_1 --dry-run ``` `eval-options` prints the criterion types, priorities, data point types, frequencies, and limits the evaluation config accepts. `eval-metrics` prints grade and tag counts for the last `--days` days (default 30). `eval-run` queues an evaluation for each `--session-id` and prints the result id to poll for each queued session, plus the sessions skipped as ineligible or already running. | Flag | Description | | - | - | | `--days` | Look-back window for `eval-metrics`, 1 to 365. | | `--session-id` | Session to evaluate with `eval-run`. Repeat for multiple sessions, up to 200. | | `--dry-run` | Print the credit cost and skipped sessions without queuing anything. | | `--json` | Print the raw response payload. | `eval-run` needs edit access on the agent and consumes one credit per queued session. # Artifacts Source: https://docs.gumloop.com/cli/artifacts List and download files produced by agents. `gumloop artifacts` exposes the [files](/core-concepts/agent_artifacts) an agent has produced — reports, generated docs, exported data, etc. Artifacts are always scoped to an agent. ## List artifacts ```bash theme={"dark"} gumloop artifacts list agent_abc gumloop artifacts list agent_abc --session session_xyz --limit 50 ``` Prints `ID`, `FILENAME`, `VERSION`, `SESSION`, and `CREATED`. If the response is paginated, the next cursor is printed at the bottom. Grab the agent ID from `gumloop agents list` and the session ID from `gumloop sessions get ` or the URL of the session in the Gumloop hub. | Flag | Description | | - | - | | `--session` | Filter to artifacts produced inside a specific session. | | `--limit` | Maximum number of artifacts to return. | | `--cursor` | Pagination cursor from a previous list call. | | `--json` | Print the raw response payload. | ## Download an artifact ```bash theme={"dark"} gumloop artifacts download artifact_abc ``` By default the artifact is written to the current directory under its original filename. Use `-o` to change the destination: | Flag | Description | | - | - | | `-o`, `--output` | File or directory to write to. Use `-` to write to stdout. | | `--version-id` | Download a specific artifact version. | | `--json` | Print download metadata as JSON (path + bytes). | ```bash theme={"dark"} gumloop artifacts download artifact_abc -o ./downloads/ gumloop artifacts download artifact_abc -o - # stream to stdout gumloop artifacts download artifact_abc --version-id av_xyz ``` # Authentication Source: https://docs.gumloop.com/cli/authentication Sign in with OAuth or an API key. The CLI stores credentials in your OS keychain. The Gumloop CLI authenticates with either an [OAuth 2.0](/api-reference/oauth) access token or a personal [API key](/api-reference/authentication#api-key). Both grant the same permissions; OAuth is recommended because it can refresh on its own. Credentials are stored in your OS keychain (macOS Keychain, GNOME Keyring, or KWallet) — never in a plaintext file. On headless machines, skip `gumloop login` and use [environment variables](#environment-variables) instead. The CLI runs on **macOS** and **Linux** only — not native Windows. On Windows, run it inside [WSL](https://learn.microsoft.com/windows/wsl/install) or use the [Python SDK](/api-reference/sdk/python) instead. See [System requirements](/cli/overview#install). ## Login ```bash theme={"dark"} gumloop login ``` Pick **OAuth (browser)** or **API key** when prompted: gumloop login prompt asking the user to choose between OAuth (browser) and API key ### OAuth (recommended) ```bash theme={"dark"} gumloop login --method oauth ``` Here's what happens: 1. The CLI starts a tiny one-shot web server on `localhost:8765` to receive the OAuth redirect. 2. Your browser opens to the Gumloop consent screen — click **Allow**. 3. Gumloop redirects back to `localhost:8765`, the CLI captures the auth code, exchanges it for tokens, and shuts the server down. 4. Both the access token and refresh token are saved to your OS keychain. Expired access tokens are refreshed automatically — you should not need to re-run `gumloop login` until you explicitly `logout`. **On a remote box** where the CLI can't open a browser: ```bash theme={"dark"} gumloop login --method oauth --no-browser ``` The CLI prints the authorization URL — open it on any machine, complete the flow, and the redirect will still land back on `localhost:8765` on the remote box (use SSH port-forwarding if needed: `ssh -L 8765:localhost:8765 user@host`). Other options: | Flag | Default | Description | | - | - | - | | `--callback-port` | `8765` | Local port for the OAuth redirect handler. Change it if 8765 is in use. | | `--no-browser` | off | Print the authorization URL instead of opening a browser. | ### API key ```bash theme={"dark"} gumloop login --method api-key ``` You'll be prompted for two values: 1. **API key** — generate one on the [Connectors page](https://www.gumloop.com/settings/profile/connectors?view=connected). Requires the Pro plan or above. 2. **User ID** — your Gumloop user ID, also visible on the [Profile Settings page](https://www.gumloop.com/settings/profile/general). Pass them inline to skip the prompt: ```bash theme={"dark"} gumloop login --api-key gum_xxx --user-id user_abc ``` To keep the key out of your shell history (and `/proc//cmdline` on Linux), pipe it in via stdin with `-`: ```bash theme={"dark"} echo "$GUMLOOP_API_KEY" | gumloop login --api-key - --user-id user_abc ``` The same `-` trick works for `--access-token`. ### Verification `gumloop login` calls a lightweight read endpoint (`models.list`) before saving anything. If the credential is invalid, nothing is written to the keychain. ## Logout ```bash theme={"dark"} gumloop logout ``` This clears every entry the CLI wrote to your keychain. If you signed in with OAuth, the CLI also revokes your refresh token server-side. Revoke failures don't block the local clear — a warning is printed if the server was unreachable. ## Environment variables These override stored credentials for a single invocation, which makes them ideal for CI, containers, and headless servers. | Variable | Purpose | | - | - | | `GUMLOOP_ACCESS_TOKEN` | OAuth access token. Wins over any stored credential. | | `GUMLOOP_API_KEY` | Personal API key. Used only if `GUMLOOP_ACCESS_TOKEN` is not set. | | `GUMLOOP_USER_ID` | User ID for API key auth (sent as the `x-auth-key` header). Required with `GUMLOOP_API_KEY`. | | `GUMLOOP_TEAM_ID` | Default team to scope commands to (same as `--team-id`). | | `GUMLOOP_BASE_URL` | Override the Gumloop API base URL (same as `--base-url`). | **Example: GitHub Actions step** ```yaml theme={"dark"} - name: Trigger nightly report env: GUMLOOP_API_KEY: ${{ secrets.GUMLOOP_API_KEY }} GUMLOOP_USER_ID: user_abc run: | curl -fsSL https://gumloop.com/cli/install.sh | sh gumloop sessions create agent_abc --input "Run the nightly report." ``` ## Where credentials are stored The CLI writes the following entries under the `gumloop-cli` keyring service: | Entry | Set when | | - | - | | `access_token` | OAuth login | | `refresh_token` | OAuth login (if the server issued one) | | `api_key` | API-key login | | `user_id` | API-key login | | `base_url` | Always — the API base URL the credentials were issued against | Inspect them with your OS tooling (Keychain Access on macOS, `secret-tool` / `kwallet-query` on Linux) or wipe them with `gumloop logout`. If no keychain backend is available, `gumloop login` refuses to run rather than fall back to a plaintext file. On a headless box, use the [environment variables](#environment-variables) above. # Brain Source: https://docs.gumloop.com/cli/brain Search your Company Brain and keep a folder of files synced into it from the terminal. [Company Brain](/core-concepts/brain) is your organization's knowledge base — the documents, messages, and files you've connected and indexed. `gumloop brain` searches it with the same hybrid (semantic + keyword) search your agents use, and syncs local folders into file-upload sources. Brain is available on the **Pro** and **Enterprise** plans. Searches and indexing consume Gumloop credits. ## Sync a folder ```bash theme={"dark"} gumloop brain sync ./docs --create "Engineering docs" ``` The first run creates a file-upload source and uploads every file in the folder (subfolders included, dotfiles skipped). Re-running compares each file's name and sha256 against the source and uploads only what is new or changed; indexing starts on its own after each upload. ```text theme={"dark"} Source PFqdAMir8PA2Xc6qcszSN9 (active) 1 uploaded, 1 replaced, 0 pruned, 3 unchanged Skipped notes.exe: unsupported file type ".exe" ``` ```bash theme={"dark"} gumloop brain sync ./docs --source --prune # existing source; remove remote files that are gone locally gumloop brain sync ./runbooks --create "Runbooks" --team-id gumloop brain sync ./policies --create "Policies" --scope organization --require-approval --approve gumloop brain sync ./docs --source --dry-run ``` | Flag | Description | | - | - | | `--source` | Id of an existing source to sync into. Exactly one of `--source` or `--create` is required. | | `--create` | Create a new source with this name. Personal by default; add `--team-id` (or `--scope team --team-id`) for a team source, `--scope organization` for an organization source. | | `--require-approval` | With `--create`: start as a draft that estimates credits before indexing (see below). | | `--prune` | Delete files from the source that no longer exist locally. Off by default. | | `--approve` | Approve a draft source once its estimate is ready. | | `--dry-run` | Print the plan without uploading or deleting. | | `--json` | Print the result as JSON (`uploaded`, `replaced`, `pruned`, `unchanged`, `rejected`, `estimate`). | Accepted file types are PDF, Word, PowerPoint, Excel, and text (`.txt`, `.md`, `.html`, `.csv`, `.rtf`), up to 25 MB each. Anything else is reported as skipped and left alone. ### Drafts and credit estimates Without `--require-approval` a source is active and each upload is indexed and billed right away. With it, the source is a draft: uploads run a credit estimate, the source owner is notified in Gumloop, and nothing is indexed until it is approved. ```bash theme={"dark"} gumloop brain sources estimate # Estimate (paused_for_approval): 5 credits for 2 files (75 tokens). gumloop brain sources approve ``` ## Sources and files ```bash theme={"dark"} gumloop brain sources list [--scope personal|team|organization] [--source-type direct_file_uploads] gumloop brain sources create "Engineering docs" [--scope team --team-id ] [--require-approval] gumloop brain sources get gumloop brain sources delete gumloop brain files list gumloop brain files upload ./handbook.pdf ./release.md gumloop brain files delete ``` `sources list` shows every source you can see, including ones connected in the app such as Notion or Google Drive. Only file-upload sources can be created from the CLI. `files list` shows each file's indexing status (`uploaded`, `indexing`, `indexed`, `failed`) and sha256. Every command takes `--json`. ## Search ```bash theme={"dark"} gumloop brain search "onboarding process" ``` The query returns the most relevant snippets across every source you can access — your Personal sources plus any Team and Organization sources shared with you. ```text theme={"dark"} SCORE SOURCE TITLE URL 0.871 notion Onboarding Checklist https://www.notion.so/Onboarding-Checklist-2f1a9c7e 0.804 google_drive New Hire Handbook https://docs.google.com/document/d/1a2b3c ``` ### Options | Flag | Description | | - | - | | `--limit` | Maximum number of results to return (1–50). Defaults to 8. | | `--source` | Filter by source type. Repeat the flag to allow several, e.g. `--source notion --source slack`. Valid values: `notion`, `google_drive`, `slack`, `github`, `confluence`, `direct_file_uploads`, `gumloop_artifacts`. | | `--json` | Print the raw response payload instead of the table. | ```bash theme={"dark"} gumloop brain search "pricing" --limit 5 --source notion --json ``` The `--json` output includes the full result objects — `document_id`, `source`, `title`, `content`, `url`, `score`, `updated_at`, `owner_name`, `owner_email`, `parent_title`, and `metadata` — which is handy for piping into `jq` or another tool. ## Related How Brain indexes your knowledge and how agents use it. Search, sources, and file uploads over the REST API. # Chat Source: https://docs.gumloop.com/cli/chat Send chat completions to any Gumloop-supported model from the terminal. `gumloop chat completions create` is the terminal counterpart of the Python SDK call `client.chat.completions.create(...)`. Every flag maps 1:1 to the matching SDK kwarg. ## Create a completion ```bash theme={"dark"} gumloop chat completions create "Capital of Canada?" -m claude-sonnet-4-5 ``` By default, output streams to your terminal when stdout is a TTY and is buffered into a single response when it isn't (e.g. piped to a file or another command). Pass `--stream` or `--no-stream` to be explicit. | Flag | Description | | - | - | | `-m`, `--model` | **Required.** Model slug (for example `claude-sonnet-4-5`, `gpt-4o-mini`, `gemini-2.5-pro`). Chat needs a concrete model, so `gumloop-chew` (the **Auto** [router](/core-concepts/ai_models#auto-faq)) is not valid here. Preview a choice with `POST /models/route` first, then complete. | | `-s`, `--system` | System message prepended to the conversation. Repeatable. | | `--message-stdin -` | Read the user message from stdin instead of the positional argument. | | `--max-completion-tokens` | Cap on completion tokens. | | `--temperature` | Sampling temperature. | | `--modality` | Output modality. Repeatable — e.g. `--modality image --modality text` for image-generation models. | | `--schema-file` | Path to a JSON Schema file. Sent as `response_format={"type": "json_schema", ...}` for structured output. | | `--schema-name` | Name to attach to the schema (defaults to `schema`). | | `--stream` / `--no-stream` | Force or suppress streaming. When omitted, streams only if stdout is a TTY. `--json` implies `--no-stream` unless `--stream` is also passed. | | `--json` | Print the response as JSON. With `--stream`, emits newline-delimited JSON (one chunk per line). | ## Pipe from stdin ```bash theme={"dark"} cat draft.md | gumloop chat completions create -m claude-sonnet-4-5 \ --message-stdin - \ --system "Summarize the input in three bullets." ``` ## Structured output ```bash theme={"dark"} gumloop chat completions create "Return JSON with the capital of Canada." \ -m claude-sonnet-4-5 \ --schema-file ./capital.schema.json \ --schema-name capital \ --json ``` `capital.schema.json`: ```json theme={"dark"} { "type": "object", "properties": { "capital": { "type": "string" } }, "required": ["capital"], "additionalProperties": false } ``` ## Image generation ```bash theme={"dark"} gumloop chat completions create "A red maple leaf on white" \ -m gpt-image-2.5-flare \ --modality image --modality text \ --json ``` The response carries one or more image attachments on `choices[0].message.images`. Each entry is a data URL the caller can decode or render directly. ## Streaming with machine output `--stream --json` emits ndjson — one full `chat.completion.chunk` per line — so consumers can stitch deltas without re-parsing the full SSE wire format. ```bash theme={"dark"} gumloop chat completions create "stream me" -m claude-sonnet-4-5 --stream --json ``` The CLI streams to TTYs by default. When redirecting stdout (`> out.txt`, `| jq`, CI pipes) it switches to unary so output is byte-stable. # Evaluations Source: https://docs.gumloop.com/cli/evaluations Create organization evaluations, choose which agents they grade, and run them over past sessions. `gumloop evaluations` manages [organization evaluations](/core-concepts/evaluations): rubrics an organization admin defines once and applies to teams, people, or individual agents. Every command accepts `--json` to print the raw response payload. These commands require the Enterprise plan and the **Manage evaluations** organization permission. Commands that need an organization default to the one you belong to; pass `--organization org_abc` to be explicit. ## List evaluations ```bash theme={"dark"} gumloop evaluations list ``` Returns a tab-separated table with `ID`, `NAME`, `ENABLED`, `AGENTS` (how many agents the targets currently cover), `GRADED`, and `SUCCESS`. | Flag | Description | | - | - | | `--organization` | Organization id. Defaults to yours. | | `--limit` | Maximum number of evaluations to return. | | `--cursor` | Pagination cursor from a previous list call. | ## Get an evaluation ```bash theme={"dark"} gumloop evaluations get eval_abc ``` Prints the name, whether it is enabled, its targets, how many agents it covers, how many criteria it has, and its graded count and success rate so far. ## Create an evaluation ```bash theme={"dark"} gumloop evaluations create --name "Support tone" gumloop evaluations create --name "Refund policy" --config-file rubric.json ``` `rubric.json` holds the rubric fields — `criteria`, `tags`, `data_points`, `model_name`, `frequency`, `language`, `session_types`: ```json theme={"dark"} { "criteria": [ { "name": "Greets the customer", "prompt": "Did the agent greet the customer by name?", "priority": "needs_review" } ], "tags": [{ "name": "refund request", "description": "The customer asked for a refund." }] } ``` | Flag | Description | | - | - | | `--name` | Evaluation name, unique within the organization. | | `--description` | Optional description. | | `--organization` | Organization id. Defaults to yours. | | `--config-json` | Inline JSON rubric. | | `--config-file` | Path to a JSON file containing the rubric. Mutually exclusive with `--config-json`. | A new evaluation starts disabled and grades nothing until you give it targets and turn it on: ```bash theme={"dark"} gumloop evaluations targets eval_abc --team-ids team_1 gumloop evaluations update eval_abc --enable ``` Unknown values — a `priority` that isn't `needs_review` or `needs_attention`, a `frequency` that isn't `debounced`, `per_turn`, or `manual`, a criterion missing `name` or `prompt` — are rejected with the offending field path rather than silently changed. `gumloop evaluations options` lists every allowed value. ## Update an evaluation ```bash theme={"dark"} gumloop evaluations update eval_abc --enable gumloop evaluations update eval_abc --disable gumloop evaluations update eval_abc --name "Support tone v2" --config-file rubric.json ``` Only the flags you pass change. A rubric list you send (`criteria`, `tags`, `data_points`) replaces that list wholesale, so send the full list you want to keep. Pass `--description ""` to clear the description. Turning an evaluation on requires at least one criterion, tag, or data point and at least one covered agent. ## Choose which agents it grades ```bash theme={"dark"} gumloop evaluations targets eval_abc --whole-organization gumloop evaluations targets eval_abc --team-ids team_1,team_2 --agent-ids agent_9 gumloop evaluations targets eval_abc --user-ids user_5 ``` Each call replaces the whole target set. Targets expand to agents live: a team target grades every agent that team owns, including ones created later; `--user-ids` grades members' personal agents. The output lists the saved targets and how many agents they currently cover. Removing the last target pauses an enabled evaluation. | Flag | Description | | - | - | | `--whole-organization` | Grade every agent in the organization. | | `--team-ids` | Comma-separated team ids. | | `--user-ids` | Comma-separated member user ids. | | `--agent-ids` | Comma-separated agent ids. | ## Run it on past sessions ```bash theme={"dark"} gumloop evaluations run eval_abc session_1 session_2 gumloop evaluations run eval_abc session_1 --dry-run ``` Queues up to 200 sessions for grading and prints one line per session: queued ones with their result id, skipped ones with the reason (`ineligible` when the session's agent isn't covered, `in_flight` when it is already being graded). Each queued session costs one credit. `--dry-run` prints the same breakdown without queuing or charging. Grading is asynchronous — check back with `gumloop evaluations results`. ## See results ```bash theme={"dark"} gumloop evaluations results eval_abc gumloop evaluations results eval_abc --grade needs_attention gumloop evaluations results eval_abc --agent agent_9 --since 2026-09-01T00:00:00Z --json ``` Returns a tab-separated table with `ID`, `SESSION`, `AGENT`, `STATUS`, `GRADE`, and `CREATED`. Failed results show their error code in the grade column. | Flag | Description | | - | - | | `--agent` | Only results for this agent. | | `--session` | Only results for this session. | | `--grade` | `pass`, `needs_review`, or `needs_attention`. | | `--status` | `queued`, `in_progress`, `completed`, or `failed`. | | `--since` / `--until` | Created-at bounds, RFC 3339 with an offset (for example `2026-09-01T00:00:00Z`). | | `--limit` | Maximum number of results to return. | | `--cursor` | Pagination cursor from a previous call. | ## Metrics ```bash theme={"dark"} gumloop evaluations metrics eval_abc --days 7 ``` Prints how many sessions received each grade in the window (default 30 days). ## Delete an evaluation ```bash theme={"dark"} gumloop evaluations delete eval_abc ``` The evaluation stops running and disappears from lists. Results it already produced stay attached to their sessions. # MCP servers Source: https://docs.gumloop.com/cli/mcp Explore the MCP servers available to your account and execute their tools. An [MCP server](/nodes/mcp/custom_mcp_servers) is an integration — Gmail, Slack, Linear, Notion, your own custom one — that exposes a set of tools your agents (or you, directly) can call. `gumloop mcp` lets you list the servers connected to your account, browse their tools, and invoke them on demand. ## List servers ```bash theme={"dark"} gumloop mcp list ``` Prints `SERVER_ID`, `NAME`, `TYPE`, `STATUS`, `TOOLS` (tool count), and `AUTH_URL`. If a server's `STATUS` is anything other than `connected`, the `AUTH_URL` column has a one-click link to finish connecting it — open it in your browser, approve, and you're done. ## Inspect a server ```bash theme={"dark"} gumloop mcp get gmail ``` Shows the server's full configuration — `server_id`, `type`, `status`, `tool_count`, `description`, the Gumloop auth URL, and the underlying MCP endpoint. ## List the tools a server exposes ```bash theme={"dark"} gumloop mcp tools gmail ``` Returns a table of `NAME`, `TOOL_CALL_ID`, and `DESCRIPTION`. If the server isn't connected yet, the CLI prints the auth URL you need to open instead. You pass the tool's `NAME` (not `TOOL_CALL_ID`) to `gumloop mcp call`. `TOOL_CALL_ID` is the internal identifier used when an agent invokes the tool. ## Call a tool ```bash theme={"dark"} gumloop mcp call gmail list_emails --args-json '{"max_results": 5}' ``` The arguments can come from three places (pick one): | Flag | Description | | - | - | | `--args-json` | Inline JSON object. | | `--args-file` | Path to a JSON file. | | `--args -` | Read JSON from stdin (use the literal `-`). | | `--ref` | Optional client-side ref string. The server echoes it back on each result so you can match responses to requests. | | `--json` | Print the raw response payload. | Examples: ```bash theme={"dark"} gumloop mcp call gmail send_email --args-file ./email.json ``` ```bash theme={"dark"} cat email.json | gumloop mcp call gmail send_email --args - ``` The default text output groups results by tool, prints the status and any error, then the content of each result. MCP execution failures are reported per result, so check each printed `status` or use `--json` to pipe the structured response into another tool. # Gumloop for terminal Source: https://docs.gumloop.com/cli/overview Drive Gumloop agents, sessions, chat completions, MCP servers, Company Brain, skills, and artifacts from your shell. `gumloop` is the command line for Gumloop. Sign in once, then drive your agents, sessions, chat completions, MCP integrations, Company Brain, skills, and artifacts from the terminal. Every command has a `--json` mode so you can pipe results into scripts, cron jobs, or any other tool you already use. ## Install ```bash theme={"dark"} curl -fsSL https://gumloop.com/cli/install.sh | sh ``` The prompt is self-contained — the agent installs the CLI, sorts out authentication with you, and installs the [Gumloop CLI skill](#use-with-coding-agents) on its own. ````markdown theme={"dark"} # Set up the Gumloop CLI Set up the Gumloop CLI in this environment so you can operate Gumloop (run agents, call MCP integration tools, search Company Brain). Follow these steps in order. ## Step 1: Install the CLI Skip this step if `gumloop --version` already works. Otherwise install it (macOS, Linux, or WSL only — it does not run on native Windows): ```bash curl -fsSL https://gumloop.com/cli/install.sh | sh ``` On an interactive machine the installer ends by offering `gumloop login` — tell me to accept it. On a headless machine or CI, ask me for a Gumloop API key (from https://www.gumloop.com/settings/profile/connectors?view=connected) and my user ID (from https://www.gumloop.com/settings/profile/general), then export both as `GUMLOOP_API_KEY` and `GUMLOOP_USER_ID`. Never print or log the API key. ## Step 2: Verify authentication ```bash gumloop agents list ``` If this fails with an authentication error, fix the credentials from Step 1 before continuing. ## Step 3: Install the Gumloop CLI skill ```bash gumloop plugin install gumloop ``` This installs a `gumloop-cli` skill with the full command reference into your skill directories. Read it before using unfamiliar commands. ## Step 4: Learn the surface - List what is available: `gumloop agents list`, `gumloop mcp list`. - Always pass `--json` when you parse output. - Use `gumloop --help` before using a command; do not invent flags. - Discover MCP tools with `gumloop mcp tools --json` instead of guessing tool names. When all steps pass, tell me what agents and MCP servers you found and ask what I want to run first. ```` The installer is fully self-contained under `~/.gumloop` — it ships its own Python, never touches your system Python, and needs no sudo. Verify the install: ```bash theme={"dark"} gumloop --version ``` Update any time with: ```bash theme={"dark"} gumloop update ``` Using Gumloop as a library instead? See the [Python SDK](/api-reference/sdk/python). **Windows is not supported.** The Gumloop CLI runs on **macOS** and **Linux** only. This applies to every command — including `gumloop login` and syncing skills or artifacts — because credential storage and the OAuth callback server rely on POSIX-only paths. Windows users have two options: * **Use [WSL](https://learn.microsoft.com/windows/wsl/install)** (Windows Subsystem for Linux) and install the CLI inside your Linux distribution. This is the recommended path. * **Use the Python SDK instead** — it works natively on Windows. Import `from gumloop import Gumloop` directly. See the [Python SDK reference](/api-reference/sdk/python). ### Linux prerequisites The CLI stores credentials in your OS keychain. macOS Keychain is always available, but on Linux you need one of: ```bash theme={"dark"} sudo apt install gnome-keyring libsecret-1-0 sudo apt install kwalletmanager ``` On a headless box without a keychain, skip `gumloop login` entirely and pass credentials per invocation via [environment variables](/cli/authentication#environment-variables). ## Sign in ```bash theme={"dark"} gumloop login ``` Pick **OAuth (browser)** at the prompt. The CLI opens your browser, you click "Allow" on the Gumloop consent screen, and you're signed in. Tokens are stored in your OS keychain and the CLI refreshes them for you when they expire. Prefer an API key, or running on a headless box? See [Authentication](/cli/authentication). ## Your first command List the agents you can see: ```bash theme={"dark"} gumloop agents list ``` ```text theme={"dark"} ID NAME MODEL TEAM ACTIVE agent_g6f1a2b3 Sales research anthropic/claude-sonnet-4 team_4f8c92ab yes agent_h7e9c1d4 Support triage openai/gpt-5 team_4f8c92ab yes ``` Grab an ID from that table and start a chat: ```bash theme={"dark"} gumloop sessions create agent_g6f1a2b3 --input "Summarize this week's pipeline." ``` That's it. From here, every command works the same way — `gumloop `, with `--help` on anything to see all the flags. ## Use with coding agents Now that you're set up, your coding agent (Claude Code, Cursor, Codex, ...) can drive Gumloop for you. One command installs the `gumloop-cli` skill — setup, every command, and the sharp edges — into each coding agent detected on your machine: ```bash theme={"dark"} gumloop plugin install gumloop ``` Restart your agent (or start a new session) and it picks the skill up whenever a task involves Gumloop. Haven't installed the CLI yet? The [setup prompt in Install](#install) has your agent do all of this for you. The skill ships inside the CLI as an [Agent Plugin](https://agent-plugins.org). To write the raw plugin package (`plugin.json` + `skills/`) somewhere explicit — for a plugin-aware client or a project checkout — use `gumloop plugin install gumloop --dir `. ## Commands | Command | What it does | | - | - | | [`gumloop login`](/cli/authentication#login) / [`logout`](/cli/authentication#logout) | Manage stored credentials | | [`gumloop agents`](/cli/agents) | List, inspect, create, and update agents, and export agent versions | | [`gumloop sessions`](/cli/sessions) | Create, inspect, send messages to, and cancel agent sessions | | [`gumloop evaluations`](/cli/evaluations) | Create organization evaluations, choose which agents they grade, and run them over past sessions | | [`gumloop chat`](/cli/chat) | Send chat completions to any supported model (unary, streaming, structured, image) | | [`gumloop mcp`](/cli/mcp) | Explore connected MCP servers and execute their tools | | [`gumloop brain`](/cli/brain) | Search your Company Brain's indexed knowledge sources | | [`gumloop skills`](/cli/skills) | List, upload, update, and download skill files | | [`gumloop artifacts`](/cli/artifacts) | List and download artifacts produced by agents | ## Global flags These work on every command: | Flag | Env var | Description | | - | - | - | | `--team-id` | `GUMLOOP_TEAM_ID` | Scope the command to a single team. | | `--base-url` | `GUMLOOP_BASE_URL` | Override the Gumloop API base URL (useful for self-hosted/staging). | | `--version`, `-V` | — | Print the CLI version and exit. | | `--help`, `-h` | — | Show contextual help for any command or subcommand. | Most subcommands additionally accept `--json` to print the raw response payload instead of the human-friendly table, which is handy for piping into `jq`, scripts, or other tools. # Sessions Source: https://docs.gumloop.com/cli/sessions Start agent conversations, send follow-ups, and cancel running sessions. A **session** is a single conversation thread with one agent — start it, send messages back and forth, then cancel or let it finish. `gumloop sessions` is how you do all of that from the terminal. ## Create a session Start a new conversation with an agent, optionally with the first user message: ```bash theme={"dark"} gumloop sessions create agent_abc --input "Hello!" ``` Read the message from a file or stdin to avoid escaping: ```bash theme={"dark"} echo "Summarize this thread:" | gumloop sessions create agent_abc --input-stdin - ``` ```bash theme={"dark"} gumloop sessions create agent_abc --input-stdin - < ./prompt.md ``` | Flag | Description | | - | - | | `--input` | Initial user message text. | | `--input-stdin -` | Read the initial message from stdin. Mutually exclusive with `--input`. | | `--session-id` | Pre-assign a client-side session ID (otherwise the server assigns one). | | `--json` | Print the raw response payload. | The output shows the new session ID, the agent it's running against, its state, the creation timestamp, and the last few messages. Hang on to the session ID — you'll need it to send follow-ups. Don't have an agent ID yet? Run `gumloop agents list` to see all the agents you can talk to. ## Get a session ```bash theme={"dark"} gumloop sessions get session_abc ``` Prints the session metadata and the last five messages. Add `--json` for the full transcript. ## Send a follow-up ```bash theme={"dark"} gumloop sessions send session_abc --input "follow-up question" ``` Same input options as `sessions create`: ```bash theme={"dark"} cat next-turn.txt | gumloop sessions send session_abc --input-stdin - ``` ## Cancel a session ```bash theme={"dark"} gumloop sessions cancel session_abc ``` Stops a session that's currently running. The CLI returns the agent's final response after each `create` / `send` call but does not stream tokens as they're generated. If you need token-by-token streaming, use [`client.sessions.stream()`](/api-reference/sdk/python) from the Python SDK directly. # Skills Source: https://docs.gumloop.com/cli/skills Upload, update, and download agent skills as files. `gumloop skills` lets you manage agent [skills](/core-concepts/skills) as files on disk. Each skill is one or more files (markdown, JSON, anything) that an agent can read at runtime. ## List skills ```bash theme={"dark"} gumloop skills list gumloop skills list --search retrieval --limit 50 ``` Prints `ID`, `NAME`, `TEAM`, `USAGE` (usage count), and `UPDATED`. If the response is paginated, the next cursor is printed at the bottom. | Flag | Description | | - | - | | `--search` | Filter skills by query string. | | `--server` | Filter to skills related to a specific MCP server ID. | | `--limit` | Maximum number of skills to return. | | `--cursor` | Pagination cursor from a previous list call. | | `--json` | Print the raw response payload. | ## Create a skill Upload one or more files as a new skill: ```bash theme={"dark"} gumloop skills create ./my-skill.md gumloop skills create skills/*.md ``` The skill is created with all of the provided files atomically. The new skill ID is printed on success. ## Update a skill Replace the files attached to an existing skill: ```bash theme={"dark"} gumloop skills update skill_abc ./new-version.md ``` `update` is a **full replace**, not a merge. Any file that was attached to the skill but isn't in the new upload is removed. To add a file without losing the existing ones, pass all of them: `gumloop skills update skill_abc existing.md new.md`. Grab the skill ID from `gumloop skills list`. ## Download a skill ```bash theme={"dark"} gumloop skills download skill_abc ``` By default the file is written to the current directory under its original filename. Override the destination with `-o`: | Flag | Description | | - | - | | `-o`, `--output` | File or directory to write to. Use `-` to write to stdout. | | `--version-id` | Download a specific skill version. | | `--json` | Print download metadata as JSON (path + bytes). | ```bash theme={"dark"} gumloop skills download skill_abc -o ./local-name.md gumloop skills download skill_abc -o - # write to stdout gumloop skills download skill_abc --version-id skv_xyz ``` # Agent access Source: https://docs.gumloop.com/core-concepts/agent_access Agents have exactly **two roles**: **Owners** manage the agent, **Users** run it. Everything on this page is configured from the **Access** tab of the agent. ## Owner vs. User at a glance | | Owner | User | | - | :-: | :-: | | Run the agent and start tasks | | | | See instructions, model, connectors, skills, knowledge, subagents, secret names | | Only what Owners choose to show | | Edit any of the above | | | | Create their own triggers | | Only if Owners allow it | | Manage every trigger on the agent, including other people's | | | | Add/remove Owners and Users, change General Access | | | | Set User Permissions and Task Visibility | | | | See every task on the agent | | Depends on Task Visibility | | Delete the agent | | | As an **Owner** you tune exactly what Users can see and what they can create on the agent — and you can add as many Owners as you like to share that control. Access tab showing Owners, Users, General Access, File Sharing, Task Visibility, and User Permissions *** ## Give someone access Everyone below is added from the **Share** button at the top of the agent, which opens the **Share This Agent** modal. The same controls also live in the **Access** tab of the agent configuration. **Share** → type their email in **Add people** → pick the role next to the **Share** button → **Share**. * *Can manage this agent* = Owner * *Can use this agent* = User A direct email grant sticks: it keeps working even if General Access is lowered later. Instead of adding people one by one, set **General Access** in the Share modal. Everyone who comes in this way is a **User** — there is no role picker. Share This Agent modal with the General Access dropdown open, showing Restricted, Organization, and Anyone | Setting | Who can use the agent | | - | - | | **Restricted** | Only Owners and people added by email (personal agents only). | | **Team** | Everyone in the team the agent lives in. | | **Organization** | Everyone in your organization. | | **Anyone** | Anyone with the link, including people without a Gumloop account. | Agents that live in a team cannot be **Restricted** — Team is the floor. Click the role dropdown next to a person in the Share modal (or the Access tab): * **Promote to Owner** on a User * **Demote to User** on an Owner The last Owner cannot be demoted or removed. Add a second Owner first. *** ## User permissions Per-agent switches that control what **Users** see and what they can do with the agent. Owners always see everything. User Permissions section listing the per-agent User settings, each set to Show or Hide | Setting | Show means the User can | | - | - | | **Show Instructions** | Read the instructions the agent follows (read-only). | | **Show Model** | See which model the agent runs on. | | **Show Connectors** | See the connected apps the agent can use. | | **Show Skills** | See the skills the agent can use. | | **Show Knowledge Sources** | See the knowledge sources the agent can search. | | **Show Subagents** | See the other agents this agent can call. | | **Show Secrets** | See the **names** of the secrets the agent can use. | | **Create triggers** | Create and edit their own triggers (**Allow** / **Don't allow**). | | **Make a copy** | Duplicate the agent for themselves (**Allow** / **Don't allow**). | Three rules worth remembering: * **Visible is not editable.** Showing the instructions lets a User read the prompt, never change it. * **Hiding something does not disable it.** Hide Connectors and the agent still uses Gmail — the User just doesn't see it listed. * **Permissions are per agent, not per person.** Everyone with User access gets the same view. Out of the box every visibility setting is **Show**, and **Create triggers** and **Make a copy** are **Allow**. Organization admins can ship different defaults with [Agent Default Settings](/enterprise-features/agent_default_settings). If you switch **Create triggers** to **Don't allow** while Users already have triggers, Gumloop asks what to do: * **Keep running** — they keep firing. Users cannot create, edit, or activate triggers, but can still view, deactivate, and delete their own. * **Disable them** — they are switched off. Owners can still manage those triggers from the **Triggers** tab. Allowing creation again does **not** reactivate disabled triggers. When **Make a copy** is allowed, a User can duplicate the agent and becomes the Owner of their copy. The copy carries the **whole configuration** — instructions, model, connectors, skills, knowledge, subagents — even the parts your visibility settings hide from them, so treat copying as a separate decision from what a User can see. Turn it off if the agent's setup should not leave your control. Copying applies to the custom agents you build. [Gumball](/core-concepts/gumball) and Gumloop's built-in agents cannot be copied, and an organization custom role that restricts agent modification blocks copying too. **Example setup — an internal support agent everyone talks to:** General Access **Organization**, *Show Instructions* **Hide**, *Show Connectors* **Show**, *Create triggers* **Don't allow**. *** ## Task Visibility A **task** is one conversation with the agent. Task Visibility section with the dropdown open, showing Their tasks only and Team tasks | Option | What Users see | | - | - | | **Their tasks only** | Each User sees only the tasks they created. | | **Team tasks** | Users can **read** tasks created by team members. Continuing someone else's task still requires Owner access. | * This setting only exists on **team agents**, and new team agents default to **Team tasks**. * On a personal agent, Users see only their own tasks, so the setting is hidden. * Owners always see every task on either kind of agent, and any task can also be shared separately. Seeing a task includes its task-linked artifacts. It never grants access to another person's private persistent workspace files. *** ## File sharing **Default behavior** sets sharing for every file the agent generates. File Sharing section with the Default behavior dropdown open, showing Default, Organization, and Anyone | Option | Generated files are shared with | | - | - | | **Default** | Whoever can see the task and the agent — a file created in a team task is visible to that team. | | **Organization** | Everyone in your organization. | | **Anyone** | Anyone with the link. | See [Agent Artifacts](/core-concepts/agent_artifacts). *** ## Requesting and claiming access A User who needs to manage the agent opens the **⋮** menu in the agent header and chooses **Request Owner access**, then picks which Owner receives it. That Owner approves or denies it from their inbox. See [Request Owner Access](/help/sharing/request-owner-access). If an agent's Owners are unavailable, an organization admin in the same organization can manage it through administrative access and claim durable ownership. Claiming does not require every existing Owner to be gone: it changes the canonical creator and adds an Owner grant, and existing Owners remain. See [Claim an ownerless agent](/help/sharing/claim-an-ownerless-agent). Organization admins can reach any agent in the organization through their admin override, even without a grant. Admin access is **not** the same as being an Owner — that's why **Claim Ownership** exists. *** ## FAQ They no longer apply to agents. An editor becomes an **Owner**; a viewer or use-only person becomes a **User** whose visibility you tune with User Permissions. Skills still use Editor, Viewer, and Use Only. See [Sharing a skill](/core-concepts/skills#sharing-skills). No. Every User Permission is about seeing, not editing. Editing the agent requires Owner. Not today. User Permissions are per agent, not per person. If one person needs more, make them an Owner, or make a copy of the agent with different settings. An agent always needs someone who can manage it. Add a second Owner first, then demote or remove the original. An organization admin can open it and use **Claim Ownership** to take it over. *** ## Related The agent builder, tab by tab. Who can create triggers, and what happens when you turn that off. Quick answer with the eight settings. Owner vs User, and roles on skills. # Agent artifacts (files) Source: https://docs.gumloop.com/core-concepts/agent_artifacts How agent-generated files are versioned, shared, hosted, and made interactive