# Chipp AI: Complete Documentation > Chipp is a platform that builds AI agents and software. It does your annoying work so you can do what matters. - Canonical definition of an autonomous company: https://chipp.ai/blog/what-is-an-autonomous-company - Website: https://chipp.ai ## Plans Every plan includes every feature. The only difference is who does the build. - Do it yourself: $299 per month. You build it. Start from a template or a blank page, with help docs, how-to videos, and the community Slack. - Configure your template: $299 per month, plus $2,500 one time. We set it up, you run it. We configure a template on your data and tools and train your team. - Custom build: $299 per month, plus custom scope. We build custom AI and software for you. The scope is agreed before we start, and it runs on the same platform. $100 of AI usage is included every month. Usage above that is paid as used. Details: https://chipp.ai/pricing ## Key pages - [Chipp Home](https://chipp.ai): What Chipp is and how it builds AI agents and software for you - [Pricing](https://chipp.ai/pricing): Three plans at $299 a month, with $100 of AI usage included - [Customers](https://chipp.ai/customers): Customer stories with real numbers - [Blog](https://chipp.ai/blog): Product updates, tutorials, and ideas on how autonomous companies work - [About Chipp](https://chipp.ai/about): Who Chipp is, who founded it, and how the company works - [Alchemist](https://chipp.ai/alchemist): The autonomous software factory that plans, builds, tests, and ships production software - [Documentation](https://chipp.ai/docs): How to build, publish, and run agents and software on Chipp - [Events](https://chipp.ai/events): Upcoming Chipp workshops and conferences - [Templates](https://chipp.ai/templates): Templates to start from: AI agent templates and full-stack app templates, with live demos - [Integrations](https://chipp.ai/integrations): The tools and data sources Chipp connects to - [AI Glossary](https://chipp.ai/ai/glossary): AI concepts explained for builders and businesses - [Enterprise](https://chipp.ai/enterprise): Chipp for large organizations: security, scale, and custom builds - [Security](https://chipp.ai/security): How Chipp protects customer data and handles compliance - [Contact](https://chipp.ai/contact): Talk to the Chipp team ## Customer stories - [Valor Victoria](https://www.youtube.com/watch?v=je-yfEtaCCc): Replaced its offshore engineering team in 30 days. Team size 50 → 3. 30 days to EBITDA positive. $5M+ of offshore spend replaced. - [MACE / Matthias](https://chipp.ai/blog/mace-ai-content-engine): Matthias built an AI content engine with the MACE template. 1 day from idea to a working content engine. All stories: https://chipp.ai/customers > This file also contains all Chipp documentation concatenated into a single file for LLM ingestion. > Each docs page is also available as markdown at /docs/.md on the same site. > Short index of the site: https://chipp.ai/llms.txt ============================================================ SECTION: Alchemist Platform ============================================================ # Alchemist Architecture: The Two Planes How Chipp's Alchemist separates the autonomous development plane (AI agents that plan, build, test, review, and deploy) from the production application plane (what actually runs). AI does the engineering work; it does not have to run in your deployed software. --- Chipp's Alchemist platform is an autonomous software-development and delivery system. It is easiest to understand as two separate planes: the **development plane**, where AI agents do the engineering work, and the **production plane**, where the software they build actually runs. The two are independent. AI agents write, test, and ship the code; the code itself does not have to contain any AI at all. > **Note:** This page is about how Alchemist is structured, not a tutorial. To ship your > first change, see [Alchemist: Getting Started](/docs/guides/alchemist-getting-started). > For the ticket-to-deploy mechanics, see [Alchemist Tickets: Autonomous Development](/docs/guides/alchemist-tickets). ## The autonomous development plane This is where the engineering work happens, and it is entirely AI-agent driven: 1. **Intake.** A request comes in from the dashboard, the API, or a connected Slack workspace. Slack and chat are optional intake and governance surfaces here, not a production dependency; you can dispatch every ticket from the dashboard or API and never touch chat. 2. **Project agent.** A project agent reads the request in the context of your existing codebase and conversation history and clarifies it before any code is written. 3. **Ticket and acceptance criteria.** The project agent drafts a ticket with a testable definition of done, so the outcome is judged against something concrete rather than a vague ask. 4. **Planning and execution graph.** Agents break the ticket into a graph of specialized steps instead of one long, unauditable generation. 5. **Implement.** One or more agents write the change in an isolated sandbox, against your project's real repository, with checkpoint commits to source control. 6. **Test, review, and security-check.** Independent agents exercise the change, review the diff for correctness and convention, and run an adversarial security check. 7. **Semantic merge.** The reviewed branch merges into your project's main line through source control, coordinated with any other in-flight work so nothing races or double-ships. 8. **Deploy.** A normal CI/CD pipeline builds and rolls out the merged change. 9. **Verify.** Agents check the deployed result against the original acceptance criteria, including runtime checks against the live app. Every step above is a recorded, auditable stage on the ticket, not a black box: you can see the plan, the diff, the test results, the review notes, and the verification evidence for anything that shipped. ## The production application plane This is what actually runs after a ticket lands, and it is ordinary, deterministic software. Nothing about Alchemist requires the production output to contain a chatbot, an LLM call, or any other AI component: - **APIs and backend services** that other systems call over HTTP or gRPC. - **Service-to-service integrations** that connect your existing systems. - **Workers and background job processors.** - **Scheduled jobs and cron-style tasks.** - **Event processors** that consume a queue or webhook stream. - **Data pipelines** that move and transform data between systems. - **Conventional web applications**, with or without a chat surface. See [Alchemist Production Workloads: Non-Chat Examples](/docs/guides/alchemist-production-workloads) for a concrete ticket example of each of these. A published Chipp chat agent (an AI-powered conversational app) is one thing Alchemist can build and operate for you. It is a supported use case, covered in depth elsewhere in these docs (see the **Agent Capabilities**, **Publish & Share**, and **Voice & Phone** categories), but it is not the definition of the platform. If your ticket asks for a REST endpoint, a nightly ETL job, or a webhook handler with zero natural-language surface, Alchemist builds and ships exactly that, and no AI runs anywhere in the resulting service. ## Why the split matters Because the two planes are independent, you can adopt Alchemist for its engineering throughput (agents doing the work of planning, coding, testing, reviewing, and shipping) without changing what your production architecture looks like or introducing an AI dependency into a system that has to behave deterministically. The AI agents are part of how the software gets built and maintained; they are not part of what the software has to be. ## Related reading - [Alchemist: Getting Started](/docs/guides/alchemist-getting-started) -- create a project and ship your first ticket. - [Alchemist Production Workloads: Non-Chat Examples](/docs/guides/alchemist-production-workloads) -- concrete tickets for APIs, workers, jobs, and pipelines. - [Alchemist Tickets: Autonomous Development](/docs/guides/alchemist-tickets) -- the ticket-to-deploy lifecycle in detail. - [Alchemist: Working with Tickets](/docs/guides/alchemist-working-with-tickets) -- how to describe work and respond when an agent asks a question. --- # Alchemist: Runtime, Data, and Regions What your Alchemist app runs on, the runtime rules it runs under, where its data lives, how that data is backed up, and how AI calls through the platform handle your data. --- This page collects the facts teams usually ask about before they commit to hosting an app on Alchemist: the runtime, where data lives, what is backed up, and how AI calls handle your data. ## The runtime Every Alchemist app runs as a **Deno** program (TypeScript) in a container the platform builds and manages. The same rules apply to every project: - **Fixed entry point.** The platform starts your app's `main.ts` itself. You cannot change the container command or bring your own image. - **Non-root, read-only filesystem.** The app runs as an unprivileged user on a read-only filesystem, with no write access by default. Store files in your project's storage bucket (see below), not on local disk. - **Network, environment, and file reads are allowed**; native libraries (FFI) are not. - **No subprocesses by default.** An app cannot start other programs unless Chipp grants a specific, reviewed command (for example a document renderer). **Python, Node, shells, and other language interpreters are never allowed**, even as a subprocess. If you are bringing existing code in another language, plan to port the parts that run in production to TypeScript. Tools that only run during development, such as data-preparation or analysis scripts, can stay in their original language outside the app. For CPU and memory per resource class, replicas, background workers, and the 10-minute request time limit, see [Deploys and Domains](/docs/guides/alchemist-deploys-and-domains#deployment-configuration). ## Where your app and data live | Component | Service | Location | | --- | --- | --- | | App and worker pods | Google Kubernetes Engine | Google Cloud `us-central1` (Iowa, USA) | | Database | Google Cloud SQL for PostgreSQL | Google Cloud `us-central1` | | Uploaded files | Cloudflare R2 (S3-compatible) | Cloudflare | | Cache | Redis, run by the platform | Google Cloud `us-central1` | All projects run in a single region today. There is no regional choice (for example a Canadian or EU region) yet. If you need one, contact support@chipp.ai. The database and file storage are encrypted at rest with keys managed by Google and Cloudflare respectively. ## Backups and restores | Data | What is backed up | How to restore | | --- | --- | --- | | Database | Automated daily backups plus point-in-time recovery, kept for about 7 days | Contact support@chipp.ai. Restores are carried out by Chipp, not self-serve. | | Uploaded files | **Not backed up or versioned.** A deleted or overwritten file cannot be recovered by the platform. | Keep your own copies of anything you can't lose. | | Cache (Redis) | Not persisted. Contents can be lost on any restart. | Use it only for data you can rebuild. | | Code | Every change is a commit in your project's Git repository, with full history. | Roll back a release, or revert in Git. | > **Warning:** **Rolling back a release does not restore data.** A rollback puts earlier code > back live; it does not undo database changes or bring back deleted files. If > your app holds data you can't afford to lose, add a scheduled export of your > database and files to storage you control, and test restoring from it. ## AI calls and your data Your app reaches AI models through the platform's built-in AI connection. Its credentials are injected into every deploy, so you don't manage provider keys. - **Anthropic Claude models** run on Chipp's Anthropic account with **zero data retention**: prompts and outputs are not stored by Anthropic after the response, and are not used for training. The exception is the **Fable** family, which runs on a separate account where Anthropic's standard retention applies. - **Other providers** (OpenAI, xAI, Google, Cerebras, and models via OpenRouter) are available too and run under each provider's standard API terms. For confidential or regulated material, use Claude models other than Fable. ## Related reading - [Deploys and Domains](/docs/guides/alchemist-deploys-and-domains) - [Releases, the Deploy Gate, and Rollback](/docs/guides/alchemist-releases-and-rollback) - [Environment Variables](/docs/guides/alchemist-environment-variables) --- # Alchemist Production Workloads: Non-Chat Examples Concrete examples of what Alchemist can build beyond chat agents: REST APIs, backend services, service-to-service integrations, workers, scheduled jobs, event processors, data pipelines, and conventional web applications. AI does the engineering; no AI has to run in the resulting software. --- import Callout from "../../../components/docs/Callout.astro"; Alchemist builds and ships software through tickets. AI agents do the engineering work; what they produce runs as ordinary, deterministic software. This page covers the range of production workloads you can ask Alchemist to build, with concrete examples for each type. > **Note:** None of the workload types below require an AI, LLM, chatbot, or conversational > interface in the deployed runtime. The AI is on the engineering side (planning, > coding, testing, reviewing, deploying). The software it ships can be as conventional > as any service written by a human developer. See [Alchemist Architecture: The Two > Planes](/docs/guides/alchemist-architecture) for the full structural breakdown. ## REST APIs and backend services Alchemist can build and maintain HTTP APIs that other systems call: - **Internal APIs** that expose business logic to a frontend or mobile app. - **Partner APIs** that external services call on a published schedule or event. - **Admin APIs** that back an internal tooling surface (dashboard, operations console). - **Webhook receivers** that accept inbound calls from third-party services (Stripe, GitHub, Twilio, etc.) and process them against your data layer. **Example ticket:** "Add a `POST /api/orders/bulk-import` endpoint that accepts a JSON array of order objects, validates each against the order schema, writes valid rows to the `orders` table, and returns a summary of successes and failures." ## Backend services Alchemist can build self-contained services that run independently of any UI: - **Calculation services** that other services call for pricing, routing, or scoring. - **Transformation services** that normalize and enrich incoming data before it reaches a database or downstream system. - **Auth and token services** that issue and validate credentials for internal callers. **Example ticket:** "Build a `pricing-service` that accepts a `cart_id`, fetches applicable discount rules from the `promotions` table, calculates the final total, and returns a breakdown. Expose it over an internal HTTP endpoint." ## Service-to-service integrations Alchemist can write the glue code that connects two existing systems: - **CRM-to-billing sync**: push customer status changes from Salesforce to Stripe. - **Inventory-to-warehouse**: write order lines from your ERP into a 3PL's API. - **Identity bridge**: replicate user records between an IDP and an internal users table on a schedule or triggered by a webhook. **Example ticket:** "When a Salesforce `Account` is marked `Churned`, call the Stripe API to cancel all active subscriptions for that account's customer ID and write a row to `churns_log` with the timestamp and reason." ## Workers and background job processors Alchemist can build persistent workers that consume from a queue or topic: - **Queue consumers** (SQS, RabbitMQ, Kafka, Pub/Sub) that process messages and write results to a database or downstream API. - **Retry workers** that pick up failed operations from a dead-letter queue and re-attempt them with backoff. - **Batch processors** that drain a work queue in parallel within a time window. **Example ticket:** "Build a worker that reads `image_resize` messages from the SQS queue, fetches the source image from R2, resizes it to three target dimensions, writes each variant back to R2, and marks the job `complete` in the `image_jobs` table." ## Scheduled jobs and cron-style tasks Alchemist can build and schedule periodic jobs: - **Nightly aggregation jobs** that roll up daily metrics into a reporting table. - **Reconciliation jobs** that compare two system states and log or resolve discrepancies. - **Cleanup jobs** that purge soft-deleted rows or expired sessions on a schedule. - **Export jobs** that generate and deliver CSV, JSON, or PDF reports to an S3 bucket or FTP target. **Example ticket:** "Run a cron job at 03:00 UTC every day that queries `orders` for the prior 24 hours, aggregates revenue by SKU category, and upserts the results into `daily_revenue_summary`. Send an error notification to the `#data-alerts` Slack channel if the job fails." **How scheduled jobs run.** The platform has no separate cron service: a scheduled job is a timer loop inside your app. When your app runs more than one pod, every pod runs that loop, so each tick must take a short-lived lock first so only one pod does the work. Use a Redis `SET NX EX` lock on the pre-injected `REDIS_URL`, not a Postgres advisory lock: database connections go through a transaction pooler, and an advisory lock held by a pod that dies mid-tick can stay stuck and silently stop the job on every pod. For long or heavy jobs, run them in a [background worker](/docs/guides/alchemist-deploys-and-domains#background-workers) so deploys of your web pod don't interrupt them. ## Event processors Alchemist can build event-driven pipelines that react to state changes: - **Domain event handlers** that listen for internal events (user created, order placed, payment failed) and trigger downstream actions. - **CDC processors** that react to database change streams. - **Webhook fan-out services** that receive a single inbound event and dispatch it to multiple downstream consumers. **Example ticket:** "Subscribe to the `payment.failed` event on the internal event bus. For each failure, look up the subscription record, increment the `failure_count`, and trigger a retry if `failure_count` is less than 3; otherwise mark the subscription `suspended` and enqueue a dunning email." ## Data pipelines Alchemist can build ELT/ETL pipelines that move and transform data between systems: - **Ingestion pipelines** that pull from a source API or file drop, transform the records, and write to a data warehouse or analytics DB. - **Sync pipelines** that keep two databases consistent with incremental change detection. - **Reporting pipelines** that join multiple tables, apply business rules, and materialize summary tables for a BI tool. **Example ticket:** "Build a nightly pipeline that pulls Shopify orders placed in the last 24 hours via the REST API, joins them against the `customers` table in Postgres, and writes the enriched rows to the `shopify_orders` BigQuery table, replacing any existing rows for the same order ID." ## Conventional web applications Alchemist can build and maintain web applications that have no conversational interface at all: - **Internal admin dashboards** for operations, support, or finance teams. - **Partner portals** where external companies log in and manage their account data. - **Consumer-facing apps** with forms, tables, charts, and standard CRUD workflows. **Example ticket:** "Build an internal operations portal at `/ops` that shows a paginated, filterable table of all open support tickets from the `tickets` table, lets an admin change the `assignee` field inline, and shows a sidebar with daily open/closed counts." ## Related reading - [Alchemist Architecture: The Two Planes](/docs/guides/alchemist-architecture) -- how the development side (agents, tickets, review) and the production side (whatever you actually deploy) stay completely separate. - [Alchemist: Getting Started](/docs/guides/alchemist-getting-started) -- create a project and ship your first ticket. - [Alchemist Tickets: Autonomous Development](/docs/guides/alchemist-tickets) -- the full ticket-to-deploy lifecycle. --- # Alchemist Tickets: Autonomous Development How the Alchemist platform plans a ticket as a workflow graph, executes it node by node, and how to read status, cancel, and retry. --- The Alchemist platform at build.chipp.ai is an autonomous development system. You describe what you want as a **ticket**; a team of AI agents plans the work, writes the code in an isolated sandbox against your project's real repository, reviews and security-checks it, verifies it against your acceptance criteria, merges it, and deploys it to your live app. You watch the whole thing happen live and stay in control of budget and approvals. > **Note:** "Alchemist" names two related things. This guide covers the **Alchemist platform**: the ticket-driven autonomous development system. The **Alchemist copilot** is the chat assistant inside the Chipp app builder; see [The Alchemist Copilot](/docs/guides/alchemist). ## Dispatching a ticket A ticket is a title plus a description of what you want: a feature, a fix, a refactor, or an investigation. The better the description states the goal and how you would judge it done, the better the result. You can dispatch one: - **From the dashboard** at build.chipp.ai, with **+ New ticket** on your project's Tickets page. - **From a connected Chipp agent**: any Chipp app connected to your Alchemist workspace can dispatch tickets mid-conversation, so "file a ticket to fix that" works from chat. This includes your project's own agent in Slack. See [Your Project's Agent in Slack](/docs/guides/alchemist-slack). - **Programmatically over MCP**: the platform exposes `dispatch_ticket`, `list_tickets`, `get_ticket`, and related tools to any MCP client authenticated with your tenant API key. See the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide for connection instructions. Tickets get a reference like `PROJ-42` and show up immediately in the Tickets list. ## A ticket is a workflow graph, not a fixed pipeline Every ticket runs as its own **graph of nodes**: a small, dispatch-time-planned DAG (directed acyclic graph), not a fixed sequence of stages that every ticket marches through identically. When you dispatch a ticket, a planning step reads the ticket and your codebase and proposes a graph shaped for that specific piece of work: a one-line copy fix might plan a short chain of research, implement, and review; a larger feature might plan multiple implementation nodes feeding independent review, security, and verification nodes before anything lands. The plan is checked for safety before it runs (for example, any node that writes to your repository always has an independent review path downstream, and a graph that changes code always ends in a landing node) and, on the rare case planning itself fails, the platform falls back to a safe default shape rather than leaving the ticket stuck. This replaces an older, retired fixed-stage pipeline design. If older material described a different, rigid sequence of stages, it no longer reflects how tickets execute. ## Node kinds, in builder terms The ticket detail page draws the graph as boxes and arrows; each box is a **node** with a **kind** that tells you what it is doing: - **Plan / contract**: the planning step itself, and a step that pins down a concrete, testable definition of "done" before any code is written. - **Research / investigation**: read-only exploration of your codebase, logs, or database. Nothing changes here; it is how agents ground the plan in how your app actually works today. - **Implement**: writes code in an isolated sandbox on a dedicated git branch for the ticket, committing checkpoints as it goes. - **Docs / integration**: variants of implementation work scoped to documentation changes or to wiring pieces together across a larger change. - **Review / security / verification / QA authoring**: independent nodes that read the diff (not write it): a correctness review, an adversarial security check, and a check that the contract's testable assertions actually hold, including runtime checks against a running instance of your app where relevant. - **Reconcile**: a node that resolves conflicting or partial results from earlier nodes before the graph proceeds. - **Merge repair**: only appears if landing hits a conflict; it repairs the branch so the merge can complete instead of leaving the ticket stuck. - **Land**: merges the finished branch into your project's base branch (`staging` on most projects). This step runs on the platform's own infrastructure, not inside an agent's sandbox. - **Deploy verify**: a follow-up check the platform appends automatically after a land triggers a deploy, confirming the deploy actually succeeded before the ticket is marked done. Not every ticket's graph uses every kind above. A read-only "investigate" ticket, for example, plans only research nodes and never touches your repository. ## Reading the graph The ticket detail page shows the live graph, a session audit of every agent turn, per-node reports, and running cost against the ticket's budget. Each node carries a status as it executes: - **queued**: waiting for its turn (either it has unmet dependencies, or a worker has not picked it up yet). - **running**: actively executing. - **awaiting input**: paused on a question for you. See [Answering Agent Questions](/docs/guides/alchemist-awaiting-input) for what these look like and how to reply. - **succeeded** / **failed** / **skipped** / **cancelled**: terminal states; nothing more happens to that node. - **blocked**: waiting on another node (or another ticket, if this ticket declared a dependency) that has not finished yet. Click any node to open its detail drawer: the model it ran on, its duration, its cost, and its report. ### Stalled or failed nodes A node that sits in **queued** far longer than its neighbors is usually just waiting for fleet capacity, not stuck; the page keeps polling and will move it to running on its own. A node in **failed** status has a report attached explaining what went wrong, visible in its detail drawer; it stops that branch of the graph, and any downstream node depending on it shows as blocked until you act. There is no per-node retry button: the fix is to retry the whole ticket (see below), which resumes from the last good checkpoint rather than restarting the entire graph from scratch. ## Landing and deploying When a graph's work is verified, its land node merges the ticket's branch into your project's base branch. Base-branch changes (yours and every other in-flight ticket's) are serialized through a merge lease, so two tickets landing at once cannot race each other or silently drop one of them. Landing triggers a deploy through your project's normal pipeline exactly the way pushing to the branch yourself would; the deploy appears in your project's **Releases** tab, and a `deploy_verify` node confirms the outcome before the ticket is marked done. If a land step never completes, the work is not lost, it stays on the ticket's own branch. See [Rescuing a Stuck Ticket](/docs/guides/alchemist-stuck-ticket-recovery) to fetch it and land it yourself. If the deploy itself fails (a build error or a rollout crash, as opposed to the ticket's own work), that is a deploy problem, not a ticket problem: the platform automatically retries a deploy that looks transient up to a capped number of attempts, and the ticket page also offers a self-serve "Retry deployment" action on a failed deploy so you do not have to leave the ticket to re-trigger it. ## Cancel semantics You can cancel a ticket from the ticket page, or over MCP (`cancel_ticket`), whenever it is queued, running, blocked, blocked on credits, awaiting input, or awaiting a deploy to finish. Cancelling stops further work: no new nodes start, and a running node is torn down. It does not undo anything: whatever has already landed is a normal git commit on your base branch, inspectable and revertable like any commit, and any deploy already in flight from a prior land proceeds independently under the platform's own rollout monitoring. A cancelled ticket can be retried later. ## Retry semantics Retrying a ticket (the **Resume** button on the ticket page, or the equivalent MCP action) defaults to **resuming in place**: the platform checks for durable checkpoint state (a pushed commit on the ticket's agent branch, a graph node that already succeeded, or general progress past planning) and, when it finds one, continues the same ticket from there instead of throwing away that work. This is why most retries are cheap and fast. If the plan itself was the problem, **Start over** is an explicit, separate action: it abandons any committed work on that ticket and creates a brand-new, re-planned ticket instead. Use it when the underlying approach needs to change, not just an individual step. Deploy-level retries are a separate concept from ticket retries, see "Landing and deploying" above: they only re-run a failed build or rollout for a commit that already landed, and never re-open or re-plan the ticket that produced it. ## Budgets and approvals Every ticket runs under a budget. If a plan cannot fit its budget, the ticket does not silently fail or silently overspend: it parks and asks you to approve the higher amount, and only proceeds once you do. Rejecting closes the ticket with the decision recorded. For how cost estimates are produced, how per-ticket and per-project spend is tracked, and how to query costs over MCP, see [Alchemist Budgets and Costs](/docs/guides/alchemist-budgets-and-costs). Your project can also receive ticket proposals from other projects' agents via cross-project proposal links. Proposals land in the same Approvals lane and require the same explicit decision before any work starts. See [Cross-Project Proposals](/docs/guides/alchemist-cross-project-proposals) for how to file proposals to other projects (including the built-in Chipp platform support channel) and how decisions and outcomes are reported back to the proposing side. Some tickets need to change something in your live database rather than your code. These are called **data operations**, and they always require an explicit approval on the exact SQL or script text before anything touches your database. For the full lifecycle (propose, approval card, dry-run vs execute mode, reading run output, retry/decline semantics), see [Data and Script Operations](/docs/guides/alchemist-data-operations). ## Reviewing the work - **Work Review** collects completed tickets' diffs and reports for you to inspect. See [Alchemist Work Review](/docs/guides/alchemist-work-review) for what it shows and your options when a result is not what you wanted. - Per-node reports and the full agent-turn audit trail are covered in [Alchemist Reports and Audit](/docs/guides/alchemist-reports-and-audit). - Failed or blocked tickets say why, with the failing node's report attached, and can be retried (see "Retry semantics" above). ## When you'd rather do it by hand Some changes are easier to just make yourself. Your project's repository is yours: clone it, edit in Claude Code or Cursor, and push. Pushes deploy through the same pipeline as agent merges and are coordinated with in-flight agent work. See [Alchemist: Clone Your App's Code and Develop Locally](/docs/guides/alchemist-local-development), which also covers debugging your deployed app (logs and read-only database queries) straight from your editor. ## FAQ **Do agents and my own pushes conflict?** No. Base-branch changes are serialized through a merge lease, and deployments are deduplicated by commit, so the same change never ships twice and nothing races. **Can a ticket depend on another ticket?** Yes. Tickets can declare dependencies and larger scopes fan out into multiple coordinated tickets; see [Alchemist Ticket Dependencies](/docs/guides/alchemist-ticket-dependencies) for how `depends_on` and blocking work. **What does a ticket cost?** Cost is metered per ticket from actual model and sandbox usage and shown live on the ticket detail page, with the budget ceiling alongside it. See [Alchemist Budgets and Costs](/docs/guides/alchemist-budgets-and-costs) for the full picture. **What if a ticket goes wrong?** Cancel it any time from the ticket page or over MCP (`cancel_ticket`); see "Cancel semantics" above for exactly what stops and what stays. Nothing lands on your app until the land step completes, and everything that does land is a git commit you can inspect or revert. ## Next steps New to Alchemist? Start with [Getting Started](/docs/guides/alchemist-getting-started), then come back here. From this guide, the natural path is [Budgets and Costs](/docs/guides/alchemist-budgets-and-costs) → [Ticket Dependencies](/docs/guides/alchemist-ticket-dependencies) → [Work Review](/docs/guides/alchemist-work-review). --- # Alchemist Budgets and Costs How ticket cost estimates are produced, how the per-ticket budget and cost gate work, and where to see spend. --- Every ticket on the Alchemist platform runs under a dollar budget, and you see a cost estimate before you even dispatch it. This guide covers where that estimate comes from, what happens if a ticket's plan needs more than its budget, and where to check spend. For the ticket lifecycle itself, see [Alchemist Tickets](/docs/guides/alchemist-tickets). ## The pre-dispatch estimate When you fill out the ticket dialog, the dashboard fetches a cost estimate for that ticket before you click dispatch. It shows two numbers: a typical cost and a high-side cost, for example "~\$4.50 (up to \$9.00)". - **Typical** is a central estimate built from recent, similar tickets that actually completed (historical ticket cost, once enough samples exist for your project or globally); it falls back to a calibrated static estimate when there is not enough history yet. - **High** is a more conservative, higher percentile of that same distribution. It exists so the dashboard can also show your **projected balance**, that is, what your credit balance would look like after this ticket if it ran at the higher end, so you are not surprised mid-ticket. Investigation tickets (read-only, no code changes) are priced far lower than build tickets (feature, fix, refactor, integration, verification, schema-evolution), since a build ticket's graph does substantially more work. This is a preview, not a hard cap: the actual bill is metered from real usage as the ticket runs, shown live on the ticket detail page. ## The per-ticket budget Every ticket also has a budget cap, a dollar ceiling for that ticket's whole graph. You see it as the **Budget** field next to **Cost** on the ticket detail page. Most tickets never come close to it. ## The cost gate: what happens if a ticket needs more Occasionally, the plan for a ticket's graph genuinely needs more than the ticket's budget allows, for example a larger piece of work than expected once the agent has actually looked at your codebase. When that happens, the platform does not silently let the ticket overspend, and it does not silently fail it either. The ticket parks in an **awaiting budget approval** state and asks you to approve a specific, larger amount before anything more runs. From the ticket detail page you get three options: - **Approve**: requeues the ticket and re-plans it under the raised cap, resuming from where it left off. - **Reject: re-plan within cap**: gives the ticket one bounded attempt at a smaller graph that fits the original budget instead. - **Reject and fail**: terminally fails the ticket, with the decision recorded on it. If you do not respond, the ticket does not stay parked forever: after a timeout it is treated the same as a decline and terminally fails, so a forgotten approval never quietly burns your credits by sitting open. > **Note:** A budget exception is about the total size of the plan, not about something going wrong. It is your project's way of asking "this is bigger than expected, is that still worth it to you?" before spending the money. ## Seeing your spend - **Per ticket**: the ticket detail page shows live running cost (the **Cost** field) right next to its budget, updating as the ticket's nodes run. - **Per project**: your project's Usage view shows a spend-over-time chart you can split by model, pass, or category, plus a breakdown of recent spend and your highest-cost tickets. It is read straight from the same billing ledger that produces your invoice, so it always reconciles with what you are actually charged. ## Querying costs programmatically If you are wiring Alchemist into your own tooling or a Chipp agent, the platform exposes cost data over MCP: `get_credit_balance` for your current balance, and `get_project_cost` / `get_ticket_cost` for cost breakdowns by project or by ticket. See the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide for the full tool reference and how to connect. ## Next steps From here: [Alchemist Ticket Dependencies](/docs/guides/alchemist-ticket-dependencies) for structuring multi-ticket work, or back to [Alchemist Tickets](/docs/guides/alchemist-tickets) for how a single ticket executes. --- # Alchemist Ticket Dependencies Structuring multi-ticket work with depends_on: blocked-until-parents-succeed semantics, auto-cancel on parent failure, and when to split work across tickets. --- A single ticket runs as its own workflow graph (see [Alchemist Tickets](/docs/guides/alchemist-tickets)). Separately, you can also declare that one **ticket** depends on other tickets, so a larger scope of work fans out into several coordinated tickets instead of one giant one. This guide covers that ticket-to-ticket dependency layer. ## Declaring a dependency A ticket can list `depends_on`, one or more other tickets it needs to wait on. You can set this when dispatching a ticket over MCP (`dispatch_ticket` accepts `depends_on` as an array of ticket UUIDs or `#N` references in the same project, and then requires a one-sentence `depends_on_reason` naming the parent's landed output this ticket consumes); see the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide for the full tool reference. ## Blocked-until-parents-succeed A ticket with unmet dependencies is created directly in a **blocked** state and is not dispatched yet. It shows up in a dedicated Blocked section on your project's Tickets list, informational, not an alert, so you can see at a glance what it is waiting on. A blocked ticket is promoted to queued once every ticket it depends on has succeeded. For a parent that produced a code change, "succeeded" alone is not quite enough: the platform also confirms that parent's commit has actually landed on your project's base branch before releasing the dependent, so a dependent never starts working against code that technically finished but has not actually merged yet. ## Auto-cancel on parent failure If a parent ticket ends in a terminal failure (failed, cancelled, or timed out), its blocked dependents are automatically cancelled rather than left waiting forever on something that is never going to finish. This is informational, not something you need to clean up by hand. If that parent is later retried and succeeds, the platform reconciles this automatically: a dependent that was auto-cancelled because of that parent gets a recovery pass and can resume once its dependencies are actually satisfied, rather than staying stuck cancelled. You can also cancel a parent ticket yourself while it still has live, unfinished dependents. Doing so does not silently orphan them: the platform immediately surfaces the affected dependents so it is clear they are now blocked on a decision (repoint them at something else, or cancel them too) instead of quietly waiting on a parent that will never finish. ## Dependencies vs. one bigger ticket Use `depends_on` to split a scope into multiple tickets when: - The pieces are large enough that you want independent visibility into each one's status, cost, and review, rather than one long-running ticket that hides the breakdown. - A later piece genuinely needs an earlier piece's output first, for example a schema-evolution ticket that a feature ticket must wait on, so the dependency reflects a real ordering constraint, not just a to-do list. - You want to be able to approve, retry, or cancel pieces independently, for example rejecting one piece's approach without touching the others. Prefer one bigger ticket when the work is small enough, or tightly coupled enough, that splitting it just adds coordination overhead (multiple budgets, multiple approvals, multiple things to check) without giving you anything you would actually act on independently. ## Seeing the dependency graph Your project's Tickets list groups blocked tickets together and shows what each one is waiting on. For a full dependency graph and progress rollup across a multi-ticket scope, including which tickets are done, running, blocked, or failed, use the `get_scope_graph` MCP tool covered in the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide. ## Next steps Once a dependent ticket's work is in, head to [Alchemist Work Review](/docs/guides/alchemist-work-review) to inspect what landed, or back to [Alchemist Budgets and Costs](/docs/guides/alchemist-budgets-and-costs) for how spend is tracked across a multi-ticket scope. --- # Alchemist Work Review What the Work Review surface collects, how to inspect a completed ticket's diff and reports, and your options when the result isn't what you wanted. --- Work Review is your project's checklist for confirming that finished agent work is actually what you wanted, before you move on and forget to look. This guide covers what it shows and what to do when a result isn't right. ## What Work Review collects Work Review lists one row per **conversation thread** the assistant worked on, not per ticket: if a single request in Slack, email, or the dashboard fanned out into several coordinated tickets (see [Alchemist Ticket Dependencies](/docs/guides/alchemist-ticket-dependencies)), that whole scope is still one row here. Each row shows: - The thread's title and where it came from (dashboard, Slack, or email). - Its state (discussing, building, queued, done, partially done, or failed) and, for a multi-ticket thread, how many of its tickets succeeded out of the total. - When it was created, and whether it's still awaiting your review. Threads awaiting review are pulled to the top of the list and filterable by time window (last 24 hours, 7 days, 30 days, or all time). ## Inspecting a completed ticket's changes Each row links out to the underlying work: - **Verify** opens the ticket detail page for the thread's ticket (or its primary ticket, for a multi-ticket scope). That's where the actual evidence lives: the agent graph with each node's status, the per-node reports, the session audit of every agent turn, and the running cost against budget. See [Alchemist Tickets](/docs/guides/alchemist-tickets#reading-the-graph) for how to read that page, and [Alchemist Reports and Audit](/docs/guides/alchemist-reports-and-audit) for how to read the reports and audit trail themselves in depth. - **Thread** (when different from Verify) opens the original conversation the request came from, so you can see the request in its original context. Whatever landed is a normal git commit on your project's base branch: from the ticket detail page you can see exactly what changed, and it's inspectable and revertable like any commit in your repository. Once you've looked things over, check the row off as reviewed. Checking it off is just your own bookkeeping, a way to mark "I looked at this and it's fine": it doesn't change anything about the ticket or the underlying work, and you can uncheck it if you change your mind. ## When the result isn't what you wanted You have a few options from the ticket detail page, depending on how far off the result is: - **Resume the ticket.** The **Resume** button continues from the last good checkpoint rather than starting over, useful when the work is mostly right but hit a snag. See "Retry semantics" in [Alchemist Tickets](/docs/guides/alchemist-tickets). - **Start over.** Creates a brand-new ticket with no branch seeding and abandons the committed work on the old one. Use this when the underlying approach was wrong, not just an individual step. - **File a follow-up ticket.** For a result that's functionally fine but needs a different follow-on change, a new, clearly scoped ticket is often faster and clearer than trying to steer the original one further after the fact. - **Revert the commit.** Since landed work is a normal commit, reverting it (yourself, or via a ticket asking for the revert) is always on the table. > **Note:** Work Review doesn't gate anything: it's a way to stay on top of what's shipped, not an approval step blocking a ticket's execution. Approvals for budget and awaiting-input decisions happen on the Approvals panel and the ticket detail page itself; see [Alchemist Budgets and Costs](/docs/guides/alchemist-budgets-and-costs) and [Answering Agent Questions](/docs/guides/alchemist-awaiting-input). ## Next steps From here: [Alchemist Reports and Audit](/docs/guides/alchemist-reports-and-audit) for reading the evidence in depth, or back to [Alchemist Tickets](/docs/guides/alchemist-tickets) for the full ticket lifecycle. --- # Answering Agent Questions The kinds of questions an agent asks mid-ticket, where they surface, how to reply, and the secure credential submission link flow. --- Sometimes a ticket's agent genuinely needs something from you before it can keep going: a decision, a missing piece of context, or a secret it has no business seeing. When that happens the ticket pauses in an **awaiting input** state instead of guessing. This guide covers what those pauses look like and how to resolve them. ## What an agent pauses to ask about - **Ambiguity or a design choice.** The ticket's description left more than one reasonable way to build something, and the agent would rather confirm the direction than guess and redo the work. - **Missing context it can't derive from your codebase.** Something only you know, for example which of two similar services a change should target. - **A missing credential.** The work needs an API key, certificate, or other secret that isn't in your project's environment yet. The agent never asks you to paste the value into chat; it mints a secure submission link instead (see below). - **A data repair that needs sign-off.** If an agent investigating a data issue proposes a concrete fix, a specific SQL statement against your project's database, it pauses and shows you exactly what it wants to run, rather than applying it unilaterally. - **A land step that never completed.** The implementation looks done, but the final merge into your base branch didn't succeed. The ticket names the exact branch holding the work and asks you to approve a retry or land it yourself; see [Rescuing a Stuck Ticket](/docs/guides/alchemist-stuck-ticket-recovery). ## Where these surface - **A banner on the ticket detail page.** The paused ticket shows a card describing the question, with a reply form (or, for a proposed data repair, Approve, Reject, and Discuss buttons next to the exact proposed change instead of a free-text box). - **The Approvals panel** on your project dashboard lists every ticket waiting on your reply alongside proposals from your connected channels, so you can see everything needing your attention in one place without opening each ticket. - **Your connected channels.** If the ticket originated from Slack or email, the question can also reach you there, depending on how your project is wired up. See [Your Project's Agent in Slack](/docs/guides/alchemist-slack) to connect a Slack channel. ## How to reply Type your answer into the reply box on the ticket detail page (or approve/reject a proposed data repair) and submit. For most ticket kinds, your reply is delivered straight into the same ticket, which resumes automatically right where it paused: no new ticket, same thread. A small number of older ticket kinds instead dispatch a **linked follow-up ticket** carrying your answer as additional context; either way, the work stays traceable end to end from the original ticket. If you don't have a good answer yet, you can leave the ticket paused. You get reminders after about 4 hours and 24 hours. If the question is still unanswered after 7 days, the ticket closes as **Timed out**, and you can resume it later. To stop it sooner, cancel it (see "Cancel semantics" in [Alchemist Tickets](/docs/guides/alchemist-tickets)). Over MCP, the equivalent is the `reply_to_ticket` tool, covered in the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide. ## The secure credential submission link When an agent needs a credential, it never asks for the raw value in chat, in a ticket reply, or over MCP. Instead it mints a scoped, expiring link and includes it in its question. Opening that link takes you to a small form, no account required, where you submit the value(s) directly: > **Note:** You do not need a ticket to be paused to get one of these links. Ask your project's agent to add an environment variable any time, see [Adding Environment Variables and Secrets](/docs/guides/alchemist-environment-variables) for that flow. - Values you submit are **encrypted at rest and write-only**: nobody, including Chipp staff, can read a submitted secret back out of the system afterward. - On a managed project, submitted values are applied to your project's deployment environment automatically at the next deploy. - On a BYO-repo (dispatch-only) project, the value is pushed to your own secret pipeline and the deployment restarted only if an operator has configured automatic secret apply for that project. Otherwise the form tells you the value is stored but not applied, and an operator has to apply it before it takes effect. - The link expires, so it isn't a standing door into your project's secrets. > **Note:** Never paste an actual secret value into a ticket reply, a chat message, or an MCP call, even if an agent asks a leading question. If you see a request for a credential that didn't come with one of these secure links, that's a bug: reply asking the agent to mint the link properly, and don't send the value until it does. ## Next steps Once a paused ticket resumes, its follow-up runs like any other ticket, see [Alchemist Tickets](/docs/guides/alchemist-tickets) for the full lifecycle, or [Alchemist Reports and Audit](/docs/guides/alchemist-reports-and-audit) for how to read what happened next. --- # Alchemist Reports and Audit Per-node reports and the agent-turn audit trail: how to read them when verifying work or diagnosing a surprising outcome. --- Every ticket leaves two layers of evidence behind: a **report** from each node in its graph, and a full **audit trail** of every agent turn along the way. Together they're how you verify a ticket actually did what it says, or figure out what went wrong when it didn't. This guide covers both, and where to reach for them programmatically. For the graph itself (nodes, statuses, cancel/retry), see [Alchemist Tickets](/docs/guides/alchemist-tickets). For where reports fit into deciding whether finished work is good, see [Alchemist Work Review](/docs/guides/alchemist-work-review). ## Per-node reports When a node in a ticket's graph finishes (or, for a still-running node, as it progresses), it submits a report: a short outcome plus a curated write-up of what it did. On the ticket detail page, click any node in the graph to open its detail drawer, which shows: - The node's outcome, its model, duration, and cost. - A one-paragraph summary of what that node found or did. - The full report text underneath, expandable, written for a human reader, not a raw tool-call dump. A **failed** node's drawer also shows its failure reason directly, so you don't have to dig through the full report just to see why a branch of the graph stopped. These per-node reports are the actual evidence behind a ticket's outcome: a review node's report says what it checked and what it found; a security node's says what it audited; a verification node's says what it actually exercised (including, where relevant, runtime checks against a running instance of your app) and whether it passed. ## The agent-turn audit trail Below the graph, the ticket detail page also shows a **session audit**: a chronological timeline of every turn the agent(s) took while working the ticket; explanatory narration plus which tools it reached for, grouped by which node was running at the time. For an in-progress ticket this streams live as new turns happen, so you can watch a running node think in real time instead of only seeing the result once it's done. Tool call inputs and outputs themselves are intentionally left out of the narration; it's the agent's own explanation of what it was doing and why, not a raw trace. The audit trail is most useful for understanding *how* a ticket arrived at its result: which approach it tried first, whether it hit and recovered from a dead end, or why a particular node took longer than its neighbors. ## Reading them together A practical order when checking a finished (or stuck) ticket: 1. Skim the graph for any node that isn't `succeeded`, that's where to start. 2. Open that node's report first, it's the curated answer to "what happened here." 3. If the report doesn't explain enough, or a result looks surprising even though the report says success, drop into the audit trail for that stretch of the timeline to see the actual reasoning and tool usage that produced it. ## Reading them programmatically If you're pulling this into your own tooling or a Chipp agent, the same evidence is available over MCP: - **`get_ticket`** returns a curated summary plus, for finished or in-progress work, a completion or in-progress digest, already enough for most status questions. - **`get_ticket_reports`** returns the full per-node report text, the deeper layer behind that digest. - **`get_ticket_audit`** returns the per-turn narration timeline described above. See the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide for the full tool reference and how to connect a client. ## Next steps Back to [Alchemist Tickets](/docs/guides/alchemist-tickets) for the full lifecycle, or [Alchemist Work Review](/docs/guides/alchemist-work-review) for turning this evidence into a reviewed, checked-off thread. --- # Alchemist Cross-Project Proposals Let your project's agent propose tickets to another Alchemist project. Covers the built-in Chipp platform support channel, requesting access to other projects, filing proposals from chat, decision and outcome notifications, live status queries, and the sent-proposals dashboard view. --- Your project's Alchemist agent can propose tickets to another Alchemist project, not just your own. Nothing runs on the target side until that project's builder reviews and approves the proposal, so the other project stays in control of its roadmap. This guide covers the full flow from filing a proposal to learning whether the work shipped. ## The built-in Chipp platform channel Every Alchemist project comes with one outbound proposal link already wired up: a connection to the Chipp platform team's own Alchemist project. You do not need to request access or configure anything. If your project hits a platform bug, a missing capability, or a performance problem you cannot fix yourself, your agent can surface it directly to the people who can. > **Note:** The built-in platform channel is the intended support path for platform-level problems. Instead of filing a separate support ticket, tell your agent what is happening and ask it to propose a fix to the Chipp team. From a conversation with your project agent, you might say: > "We keep hitting out-of-memory errors on every deploy. Please ask the Chipp platform team to look at it." Your agent files a structured proposal into the platform team's Approvals lane. You get a confirmation in chat, and the platform team reviews it on their side. If they accept, real engineering work starts and you hear back when it ships. ## How proposals work A proposal is a ticket description, filed by your agent into another project's Approvals queue. The target project's builder sees it alongside any other pending approvals, reads the details, and decides to accept or decline. Accepted proposals become real tickets that run through the target project's full Alchemist pipeline. The source project (yours) is not involved in the execution and cannot affect it. Key properties: - **Nothing runs until approved.** Filing a proposal does not trigger any work on the target side. - **The target project stays in control.** Approvals, rejections, and prioritization are entirely the other builder's decision. - **You are notified at each milestone** (decision time and when the work ships or fails), so you do not need to watch the other project's dashboard. ## Requesting access to other projects The built-in platform link is automatic, but proposals to any other Alchemist project require an explicit connection. To request one: 1. Open your project's **Access** tab and find **Cross-project proposal links**. Click **Request a link** and enter the target project's ID (ask that project's owner for it). Or ask your project agent to request access with the target project's ID; the agent calls the `request_ticket_proposal_access` tool. Both paths send the same request. 2. Optionally include a short message for the target team and up to 5 email addresses to receive decision and outcome notifications. 3. Your request lands in the target project's **Approvals** tab. An owner on that project approves or rejects it. Until then it shows as **Pending** in your own Access tab. Once approved, your agent gains access to a `propose_ticket_to_` tool and a `check_proposal_status_` tool for that link. Only project owners (and organization owners or admins) can see and manage proposal links. Editors and viewers see a short note instead. ### Managing your links The **Cross-project proposal links** section on the Access tab shows both directions: - **This project proposes to** lists your outbound links, including the built-in platform link, plus any requests still waiting for approval. For each active link you can **Edit emails** (the decision and outcome recipients) or **Revoke** it. - **Projects that propose to this one** lists inbound links from other projects. You can **Revoke** any of them. Revoked links stay in the list, marked revoked, so you can see the history. ### What the target builder sees The link request appears as a "Link request from" card in the target project's Approvals tab. It shows your project's name, your organization's name, and your message (if you included one). The target builder approves or rejects it like any other approval. ### Revoking a link Either side can revoke a link from the Access tab. The source project revokes it under **This project proposes to**; the target project revokes it under **Projects that propose to this one**. Once revoked, the source agent loses its `propose_ticket_to_` tool for that project. Revoking a link does not affect proposals already filed and in progress. Pending proposals from a revoked link are not automatically rejected; the target builder handles any in-flight proposals manually. To reconnect after a revoke, send a new request. The link comes back only when an owner on the target project approves it. This also applies to the built-in platform link: if you revoke it, it is not re-created for you automatically. ## Filing a proposal from chat Once a link exists (either the built-in platform link or an approved outbound link), your agent can file proposals mid-conversation. Just describe the problem or request and ask your agent to propose it. Your agent will: 1. Ask clarifying questions if the description needs more detail. 2. Compose a structured proposal (title, description, acceptance criteria). 3. Call the `propose_ticket_to_` tool to file it. 4. Return a structured acknowledgment in chat: the proposal ID, the title as filed, and confirmation that it is waiting for review. **Proposal caps:** to prevent noise, each outbound link has a cap on pending proposals (proposals not yet decided). By default, each link allows up to 5 pending proposals at a time. The target project also has its own overall caps shared by every source (by default 25 pending proposals and 10 proposals filed in any rolling hour). If your agent tries to file a proposal that would exceed a cap, it will tell you and wait. The caps reset automatically as proposals are decided. ## How decisions come back When the target builder decides on your proposal, you are notified over these channels: - **Email:** one message per decision, sent to the addresses on the link's notify list. If that list is empty, the notification goes to the account email of the person who set up the link. Change the list any time with **Edit emails** on the Access tab. - **Slack:** if your project has a Slack channel configured under Alchemist notifications settings, the same decision summary posts there. ### Rejected proposals A rejection notification names the target project, the proposal title, and the decision. If the target builder included a reason, it appears in the notification and is also visible in the sent-proposals view and via the status tool. ### Accepted proposals An acceptance notification confirms: - The proposal was accepted and work has started. - The ticket references that were created (for example, `PROJ-42` or multiple refs if the proposal was split into coordinated tickets). - The count of tickets dispatched. ## How outcomes come back Acceptance starts work, but you need to know how that work ends. The platform sends a second notification when the dispatched ticket reaches a terminal state: - **Shipped:** the ticket merged and deployed successfully. The notification includes the ticket reference, a summary of what landed, and confirmation that the fix is live. - **Did not land:** the ticket failed or was cancelled on the target side. The notification honestly reports that the work did not ship and that the target team has been notified. It does not fake success. If a proposal dispatched multiple tickets, the outcome notification waits until all of them finish and summarizes each one, so you get one message covering the whole scope rather than one per ticket. These lifecycle notifications use exactly the same channels as decision notifications. ## Asking your agent for live status You do not need to wait for a notification. You can ask your project agent for the current status of any proposal at any time: > "What happened to the memory proposal we filed last week?" Your agent calls `check_proposal_status_` and returns a structured summary. The status field covers the full lifecycle: | State | Meaning | |-------|---------| | `pending` | Filed and waiting for the target builder to decide | | `rejected` | Declined, with the reason if one was given | | `in_progress` | Accepted; the dispatched ticket is still running | | `shipped` | The dispatched ticket landed and deployed | | `did_not_land` | The dispatched ticket failed or was cancelled | The status for accepted proposals reflects live data from the target project's ticket pipeline, so `in_progress` updates to `shipped` or `did_not_land` as soon as the ticket reaches a terminal state. If you ask without a specific proposal ID, the tool returns the 10 most recent proposals filed via that link. ## The sent-proposals view Your project's Alchemist dashboard includes a **Sent proposals** section that lists every proposal your agent has filed via outbound links. It shows: - The proposal title and the target project it was sent to. - The current state (pending, rejected, in progress, shipped, or did not land) as a colored badge. - Decision details: when the decision was made, the ticket refs created if accepted, and the reject reason if declined. This section is only visible when your project has at least one outbound link or has sent at least one proposal. If neither is true yet, the section is hidden. The view is read-only. Link requests are reviewed in the target project's Approvals tab. ## The daisy-chain pattern (agencies and whitelabel builders) Cross-project proposals are not limited to the Chipp platform link. If you run a platform for your own customers (for example, an agency whose clients each have their own Alchemist project), your customers' agents can propose tickets to your project using the identical mechanism. Your project is the target. Your customers' agents request links to your project. You approve or reject each link request from your project's Approvals tab. Once a link is active, your customer's agent can propose improvements, bug reports, or feature requests to your project's Approvals lane. You decide, and they hear back when the work ships. This gives agencies and whitelabel builders a structured channel from clients into their own development backlog, without giving clients direct access to write tickets. ## FAQ **Do proposals bypass my Approvals lane?** No. Every proposal lands in the Approvals queue and requires an explicit decision. Nothing runs until you approve. **What if the notified email address is wrong?** The notification emails are captured when the link is requested. The dashboard does not offer a way to edit them yet. **Can I file a proposal programmatically?** The `propose_ticket_to_` and `check_proposal_status_` tools are available to your project agent in chat. The Alchemist Cloud Tickets MCP server exposes `request_ticket_proposal_access` for requesting a link. See [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) for connection instructions. **Is there a webhook or push API?** Not in the current version. Email and Slack notifications plus the status tool (from chat) are the supported channels for v1. ## Next steps See [Alchemist Tickets](/docs/guides/alchemist-tickets) for how dispatched tickets execute once a proposal is approved, and [Alchemist Work Review](/docs/guides/alchemist-work-review) for reviewing finished work on your own project. --- # Data and Script Operations What a data operation is, the propose to approval to apply lifecycle, the dry-run vs execute mode, reading run output, and retry/decline semantics. --- Some tickets need to change something in your live database, not your code. Alchemist calls this a **data operation**, and it always goes through an explicit approval step before anything touches your database. This guide covers what a data operation is, what happens when you approve one, and how to read the result. ## What a data operation is A data operation is a change to your **running, live database**, not a code deploy. It's how an agent fixes bad rows a bug left behind, backfills a column, or runs a one-off script against your project's real data. It never goes through the normal commit and deploy pipeline: there's no pull request, no build, no release. It's the same kind of thing an operator would do by hand from a terminal, except an agent proposes it and you approve it. There are two shapes: - **A data repair**, plain SQL statements (insert, update, delete) proposed against your database. - **A script run**, a self-contained script (Deno, bash, or Node) for work that plain SQL can't do: a backfill that calls your own services, an outbound API replay, or a transform that needs real logic. ## The propose, approve, apply lifecycle 1. **Propose.** The agent authors the exact SQL statements or script and submits them. Nothing runs yet. For SQL, the system dry-runs the statements (executes them and rolls back) so it can show you the real affected-row counts before you decide anything. 2. **Approval card.** The proposal pauses the ticket and posts an approval card, on the ticket detail page, in the Approvals panel, and in your connected channels if the ticket came from one. The card shows the exact SQL or the full script text, the agent's rationale, and (for a script) the execution mode, see below. 3. **You decide.** Approve or decline. Nothing is ever applied without this explicit step, there's no auto-apply path for a script, and only small, purely additive SQL changes on a project that's opted in can skip straight through. 4. **Apply.** On approval, the exact statements or script you saw run server-side against your project's real database. The ticket resumes with the result. 5. **Verify.** For most data operations, the agent then runs a read-only check to confirm the database actually reached the expected end state, rather than just trusting that the apply "should have" worked. ## What clicking Approve actually does: dry-run vs execute mode For a script run, the approval card tells you which of two modes you're approving: - **Execute** (the default). Approving this makes the script perform its real writes against your live database. If the script follows the dry-run-first convention (checking for an explicit `--execute` flag before writing), the platform passes that flag so the write actually happens; a script that doesn't check for it just runs as written either way. - **Dry run only.** Approving this does *not* pass the execute flag. A script written to check for it performs no writes, it only reports what it would have done. This is for when you want to see a script's real output before deciding to commit to it. Either way, the exact script text shown on the card is what runs, verbatim, nothing is re-authored between proposal and apply. ## Reading run output and failures Once a script or SQL statement runs, the result, exit code, captured output, and duration, is written back to the ticket and to the underlying operation record. This happens whether the run succeeds or fails: a failed apply is never left blank. If a script run exits with a non-zero status, you'll see its captured output (truncated if it's long) so you can tell what went wrong, and the ticket does not get marked as successfully completed on the strength of a failed run. A ticket whose only script or data operation failed cannot be reported as fully verified; the system checks the operation's real recorded status, not the agent's own summary of what happened. ## Retry and decline semantics - **Decline** and nothing runs. The database is untouched, and the ticket records that you declined, honestly, rather than reporting it as some kind of quiet success. - **Approve a failed run's follow-up.** If a run fails, the agent can diagnose the output and propose a corrected version, you'll see a fresh approval card for the new attempt; the old failed attempt is never silently retried without your review. - Every apply is scoped to your project's own database connection. The lane never has platform-wide credentials and never reaches another tenant's data. > **Note:** Nothing ever touches your database without an explicit approval on that exact SQL or script text. If a ticket claims a data change happened, you can always find the corresponding proposal and its approval on the ticket's timeline. ## Next steps See [Answering Agent Questions](/docs/guides/alchemist-awaiting-input) for where approval cards surface and how replies dispatch follow-up tickets, or [Alchemist Tickets](/docs/guides/alchemist-tickets) for the full ticket lifecycle these approvals pause and resume. --- # Alchemist: Adding Environment Variables and Secrets Add a Stripe key or other secret directly in your project dashboard, or ask your project's agent for a secure link, no pasting values into chat, ever. --- Some environment variables come pre-injected: storage, transactional email, and session signing work out of the box, so you don't provision them yourself. Everything else, a Stripe key, a third-party API token, a feature flag, you add. There are two ways: type it directly into your project's dashboard, or ask your project's agent for a secure link. Neither one ever puts the raw value in chat. ## Pre-injected variables | Variable | Purpose | | --- | --- | | `JWT_SECRET` | Per-project secret for signing session cookies. Used by the auth middleware. | | `R2_ENDPOINT`, `R2_BUCKET`, `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY` | Cloudflare R2 (S3-compatible) credentials for uploads. Every object key your project writes MUST start with its own `R2_KEY_PREFIX`, which is per-project and pre-injected alongside them. | | `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `EMAIL_FROM` | SMTP2GO transactional email credentials. Use `EMAIL_FROM` verbatim for the From header. | The agent knows about these and reaches for them automatically when you ask for features that need storage or email, image upload, password reset emails, signup confirmations, and so on. > **Warning:** The email and storage variables above are a platform-managed group: bringing your own sender or your own storage account means overriding every variable in that group together, never just one. Setting only `EMAIL_FROM` to your own domain, for example, sends your mail through the platform's SMTP account under a sender it never verified, and delivery fails outright. Tell your project's agent you want to bring your own mail or storage account, and it walks you through overriding the whole group. ## Auth providers (opt-in) Email OTP login is always on. OAuth providers register themselves when both halves of their credential pair are present: | Provider | Variables | | --- | --- | | Google | `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` | | Microsoft | `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET` | | GitHub | `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` | Add the pair using either method below and the login page picks up the new button on the next deploy. No code change required. ## Adding your own: directly in the dashboard If you have dashboard access, this is the fastest path. Open your project at build.chipp.ai, go to the **Access** tab, and find the **Credentials** panel. It lists every variable your project knows about, grouped by integration, each with a status pill (needed or populated). Nobody, including Chipp staff, can ever read a populated value back out, the pill just flips color. - Click a row to open it and type the value into the masked **Value** field, then **Save**. That field is a single line. For a certificate, private key, or service-account JSON, use the secure link below: its form gives multi-line values a textarea that keeps pasted newlines. - Need a variable that isn't listed yet? Use **Add manually** to create a new one by name. - A banner tells you when something changed since your last deploy, so you know to redeploy before the new value takes effect. Values apply automatically at the next deploy either way. ## Adding your own: the secure link Use this when you don't have dashboard access yourself, or you're handing the job to a contractor, client, or teammate who shouldn't need a Chipp account. Ask your project's agent, in the dashboard chat or in Slack: ``` @storefront-agent I need to add a STRIPE_SECRET_KEY to this project ``` The agent mints a link and posts it back in the same conversation. Nothing else needs to happen first, you do not need a ticket running. Opening the link takes whoever has it to a small form at build.chipp.ai, no Chipp account required, and it applies the same way: automatically, at the next deploy on a managed project. - The link expires, seven days by default. Ask your agent for a shorter or longer window if you need one. - On a **BYO-repo (dispatch-only) project**, there is no deployment for Chipp to write into, so the agent gives guidance to relay to you instead of a link. Two exceptions get a link: a project where an operator has configured automatic secret apply, and a credential for the agent's own browser automation (logging into a third-party portal on your behalf), which always gets a link regardless of hosting mode. - Treat the link like a password-reset link: share it only with the person who should submit the value, and let it expire rather than reusing it. ## What NOT to commit Never commit secrets to the repo. Every variable above, platform-injected or your own, is read from the environment, not from a checked-in `.env` file. ## FAQ **Can I just tell the agent the value directly in chat?** No, and it should refuse. If an agent asks you to paste a secret value directly, that is a bug, ask it to mint the link instead, or add it yourself in the Credentials panel. **Does the secure link work outside a running ticket?** Yes. A ticket that pauses mid-run because it hit a missing credential uses this exact same mechanism, see [Answering Agent Questions](/docs/guides/alchemist-awaiting-input). The difference is you do not need a ticket running at all, you can ask proactively, any time. **What if I need more than one secret at once?** Ask for all of them in the same message. One link can collect several named values. In the Credentials panel, just add each one as its own row. ## Next steps For the mid-ticket version of the secure link, see [Answering Agent Questions](/docs/guides/alchemist-awaiting-input). For connecting your project's agent to Slack in the first place, see [Your Project's Agent in Slack](/docs/guides/alchemist-slack). --- # Alchemist: Pull Data Out of Incoming Email Give your Alchemist app its own inbound email address and have AI extract structured data from forwarded emails and their PDF, image, and spreadsheet attachments. --- Many business apps start from email: purchase orders, quote requests, shipping notices, invoices. Alchemist apps can receive that email at a dedicated address and use AI to turn each message and its attachments into rows in your app's own tables. ## What ships in your app Apps created from the Alchemist web-app, API, and MCP-server templates include the whole pipeline, **switched off** until you turn it on: 1. **Receive.** Mail sent to your app's inbound address is delivered to your app as a webhook. The route rejects every request until the platform has issued it a secret token. 2. **Capture.** Each message is stored once (duplicates are ignored), along with its attachments and the raw original, so nothing is lost even if a later step fails. 3. **Extract.** A background loop sends each new message, including PDFs, images, and spreadsheets, to an AI model through the platform's AI connection, and sorts it into one of three outcomes: data to apply, a message meant for a person, or unclear. 4. **Review.** An inbound-email dashboard lists every message with its outcome, so you can see what was extracted and what needs attention. (The API and MCP-server templates expose this as an API instead of pages.) ## Turning it on 1. **Provision the address.** Ask your project's agent to set up email ingestion, or call `provision_email_ingestion` from the [Alchemist MCP server](/docs/guides/alchemist-mcp-server). This creates your app's inbound address, its mail routing, and the secret token, which is added to your app's environment on the next deploy. Re-running it is safe: it repairs drift instead of starting over. 2. **Describe what to extract.** File a ticket describing the emails you expect and what should happen to them, for example "Each quote request has a project name, due date, and drawings as PDFs; create a draft estimate for each." The agent writes the one piece that is specific to your app: an **extraction profile** (the fields to pull out and the instructions for the model) and the tables the results go into. 3. **Point email at it.** Forward messages to the address, or have your email admin add a rule that copies a shared mailbox (for example a sales inbox) to it. Until a profile exists, received mail simply waits in the pipeline. Once the profile lands, those messages are processed. ## Good to know - Applying extracted data is written to be safe to repeat, so a retried message never creates duplicates. - Fields the model may not find are optional, so a sparse email still produces a partial result rather than a failure. - A message the model can't classify is marked *unclear* on the dashboard rather than guessed at. - Processing happens in the background, so a large attachment never runs into the [request time limit](/docs/guides/alchemist-deploys-and-domains#request-time-limit). - AI calls go through the platform's AI connection. See [Runtime, Data, and Regions](/docs/guides/alchemist-runtime-and-data#ai-calls-and-your-data) for how providers handle that data. > **Note:** **Projects created before July 6, 2026** were generated before the pipeline was > added to the templates. File a ticket asking the agent to add email ingestion > to your project; it copies in the pipeline first, then writes your profile. --- # Alchemist: Getting Started Create your first project on the Alchemist autonomous software-development platform and ship your first ticket. AI agents do the engineering; the production output can be a conventional app or service with no AI running inside it. --- Alchemist generates and operates production software for you. You describe what you want, a team of AI agents does the engineering work (planning, implementation, testing, review, semantic merge, deployment, and verification), and the platform hosts the result at a live URL. There is no IDE to install and no CI to configure -- the agents run in a sandbox, commit to your project's real GitHub repo, and the platform rebuilds and rolls out the running app on every successful merge. The AI does the building. It does not have to be part of what you run in production. A ticket can just as easily produce a backend API, a service-to-service integration, a scheduled job, an event processor, or a data pipeline as it can a web app, and none of those need to include a chatbot, an LLM call, or any other AI component in their runtime. Publishing a Chipp chat agent is one thing Alchemist can build; it is not a requirement. See [Alchemist Architecture: The Two Planes](/docs/guides/alchemist-architecture) for how the development side (agents, tickets, review) and the production side (whatever you actually deploy) stay separate. ## The lifecycle 1. **Create a project.** Each project is backed by a GitHub repo cloned from the platform template. The repo is private and owned by the platform org; you can eject it to your own org at any time. 2. **Open a ticket.** Tickets are how you ask for work -- "add a login page", "fix the bug where checkout 500s", "switch the homepage hero to a video". The platform routes each ticket to an agent. 3. **The agent runs.** Inside an isolated build sandbox, the agent plans, implements, reviews, security-checks, and documents its diff. You can follow along in the Tickets view, or close the tab and come back later -- every step is durable. 4. **The platform deploys.** When the agent's branch merges, a fresh build kicks off automatically. The new image rolls out behind the same Live URL, with a few seconds of crossover. ## Where things live - **Tickets** -- every ticket and agent run, in progress and historical. - **Project switcher** (top of the sidebar) -- pick a project. Its **Overview**, **Deployment**, and **Settings** tabs hold the repo, live URL, and per-project settings. - **Domains** -- custom domains attached to a project. - **Billing** -- credit balance, monthly usage, auto-topup, ticket charges, and funding receipts. - **API Keys** (Alchemist sidebar, under Platform) -- create, copy once, and revoke your `alch_` API keys. Owners and admins only. ## Next steps - Read **[Alchemist Architecture: The Two Planes](/docs/guides/alchemist-architecture)** to see how the autonomous development plane relates to whatever you actually deploy. - See **[Alchemist Production Workloads: Non-Chat Examples](/docs/guides/alchemist-production-workloads)** for concrete tickets (APIs, workers, scheduled jobs, data pipelines) with no chat surface at all. - Read **[Alchemist Tickets](/docs/guides/alchemist-tickets)** to understand how each ticket runs as a dynamic workflow graph, how to read node statuses live, and how to cancel or retry. Then read **[Working with tickets](/docs/guides/alchemist-working-with-tickets)** for tips on writing effective tickets and replying when an agent asks you a question. - Read **[Environment variables](/docs/guides/alchemist-environment-variables)** to see what the platform pre-injects (storage, email, JWT secret) and how to add your own. - Read **[Deploys and domains](/docs/guides/alchemist-deploys-and-domains)** to learn the difference between the Live URL and a custom domain, and how to force a redeploy. - Read **[Clone Your App's Code and Develop Locally](/docs/guides/alchemist-local-development)** to work on your project's repo by hand in Claude Code or Cursor -- no GitHub account needed, and pushing to your default branch deploys through the same pipeline as an agent merge. - Read **[API keys](/docs/guides/alchemist-api-keys)** and the **[MCP server](/docs/guides/alchemist-mcp-server)** to drive the platform programmatically or from an AI client. --- # Alchemist: Where Are My Projects? How Alchemist project visibility works across accounts, organizations, and whitelabel dashboard domains, and how to troubleshoot a project you can't see. --- Alchemist projects are scoped by two things, and only two things: 1. **The account you are signed in with** (the email address). 2. **That account's active organization** (the organization shown in the org switcher). Projects are **not** scoped by domain. There is no separate copy of your projects per domain, and nothing needs to "sync" or "mirror" between domains. ## Whitelabel and custom dashboard domains If your organization runs a whitelabel dashboard on a custom domain (for example `app.yourbrand.com`), that domain serves the exact same dashboard as `build.chipp.ai`. When you sign in on your branded domain **with the same account** and the **same organization active**, you will see exactly the same projects. If the project lists look different between the two domains, it is always one of these: - **Different account.** Many agency owners have more than one login (a personal Gmail, a company email, a demo account on their own branded domain). Each is a separate account with its own organizations. Projects created while signed in as `you@company.com` will never appear while signed in as `you@yourbrand.com`. - **Different active organization.** Your account can belong to several organizations. The dashboard only shows the active organization's projects. Use the organization switcher to change which one is active. - **The project is archived.** Archived projects do not appear in the project list at all. There is no filter to show them. ## Troubleshooting checklist 1. Check which email you are signed in with on each domain. If they differ, that is the answer: sign in with the account that created the projects. 2. Check the organization switcher on both domains and make sure the same organization is active. 3. If a project you expect is missing, check whether someone archived it. Archived projects never show in the list, so ask support if you need one back. 4. Still stuck? Ask support. Support agents can look up the account tied to your verified identity and tell you which organization your projects live in. You never need to share project IDs, tenant IDs, or account identifiers in a public channel for this. ## For agencies onboarding clients Client organizations created on your branded domain are separate organizations. They do not see your agency organization's Alchemist projects, and you will not see theirs unless you are a member of their organization. This is the intended isolation model: each client's work is private to their organization. --- # Alchemist: Working with Tickets Write effective tickets, follow the pipeline, and review the work the agents ship. --- A ticket is one unit of work. When you open a ticket, the platform spawns an agent run that executes a dynamic **workflow graph** against a fresh sandbox clone of your repo. For a full explanation of how the graph is planned, how to read node statuses live, and how cancelling and retrying work, see [Alchemist Tickets](/docs/guides/alchemist-tickets). ## What the workflow graph does Each ticket's graph is planned at dispatch time for that specific piece of work. A straightforward fix might plan a short chain of research, implement, review, and land; a larger feature typically adds security-check and verification nodes before anything lands. You watch each step live from the ticket's detail view. The main node kinds you will see on a "build" ticket: - **Research / investigation.** Read-only exploration of your codebase, logs, or the web. Nothing changes here -- this is how agents ground the plan in how your app actually works today. - **Implement.** The agent writes the change in an isolated sandbox on a dedicated git branch, committing checkpoints as it goes. A large plan may fan out across multiple implementation nodes. - **Review / security / verification.** Independent nodes that read the diff (not write it): a correctness review, an adversarial security check, and a check that the ticket's definition of done actually holds, including runtime checks against a running instance of your app. - **Land.** Merges the finished branch into your project's base branch and triggers a deploy. There is also an **investigate** mode: a read-only research flow (no code changes, no deploy) that reads the codebase -- and the web when relevant -- and posts findings back. Use it for "how does X work?" or "where would I change Y?" questions. ## Answering agent questions Sometimes an agent pauses on something only you can answer -- a business-logic ambiguity, a missing credential, a design choice that isn't in the ticket. When that happens the run moves to **Awaiting input** and you'll see a banner until you reply. Your workspace also gets an email; the project's **Notifications** tab controls who receives it. Open the ticket, find the **The agent needs your input** card, and type your answer. The agent resumes within a few seconds and continues from where it paused. Long-running tickets can pause and resume multiple times -- there's no penalty for letting one sit. You can also answer from inside an AI client using the `reply_to_ticket` tool on the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server). Never paste a credential or secret value into a reply -- if the agent asked for a key, use the secure submission link from its question instead. ## Tips for good tickets - **Describe the outcome, not the implementation.** "Users should be able to sign in with Google" beats "Add an OAuth handler to /api/auth/google". - **Reference concrete URLs or files when you have them.** - **Don't pre-decompose.** One ticket per outcome works better than a ticket per file -- the agent handles cross-file changes natively. - **Include reproduction steps for bugs.** "Click X, type Y, see Z" is worth more than a paragraph of theory. --- # Alchemist: Your Project's Agent in Slack Connect Slack to your Alchemist project. Mention your project's agent in a thread. Propose, approve, and track tickets without leaving the channel. --- Every Alchemist project has its own agent. The agent is a Chipp chat assistant. It knows your project's tickets, and it can create new ones from a conversation. Connect the agent to Slack, and your team can raise work, approve it, and watch it run, all in a channel they already use. > **Note:** This guide covers the **Alchemist project agent** in Slack. To deploy one of your own Chipp chatbots (a customer support bot, for example) to Slack, see [Slack Integration](/docs/integrations/slack) instead. ## 1. Connect your project to Slack 1. Open your project at build.chipp.ai. Go to **Connections** in the sidebar. 2. If your project has no agent yet, click **Create project agent**. This step runs once. The agent is a real Chipp app, restricted to your org's members. It lives in your org's **Alchemist Agents** workspace, never public. 3. Find the **Slack** card in the channel grid. Click **Connect Slack**. **1.** Create a Slack app from Chipp's manifest The dialog shows a JSON manifest. It comes pre-configured with your agent's name, bot permissions, and event subscriptions. Copy it. Go to [api.slack.com/apps](https://api.slack.com/apps). Click **Create New App**. Choose **From manifest**. Pick your workspace. Paste the manifest in as **JSON**. **2.** Copy your app's credentials Open **Basic Information** in your new Slack app. Copy the **Client ID**, **Client Secret**, and **Signing Secret**. **3.** Enter them in Chipp and install Paste the three values into the dialog, then save. Click **Install to Slack** and authorize the app. Only a Slack workspace admin can complete this step. **4.** Invite the agent to a channel Run `/invite @YourProjectAgent` in any channel where your team should raise tickets. Invite it to as many channels as you need. ## 2. Mention the agent to start something @mention the agent with what you want. Write to it the way you would write to a teammate. ``` @storefront-agent the cart total doesn't update after a coupon is removed ``` The agent reads the thread for context and replies there, so the channel stays clean. It may ask a clarifying question first; answer in the same thread. Once it has enough to act, it proposes the work as a ticket instead of acting on its own. Not every mention has to be a ticket. Ask it to add an environment variable and it hands you back a secure link instead, see [Adding Environment Variables and Secrets](/docs/guides/alchemist-environment-variables). ## 3. Approve or reject the proposal Before any work starts, the agent posts a card describing the ticket it wants to open, with two buttons: **Approve** and **Reject**. Nothing runs until someone clicks Approve. ``` Agent: [card] Fix: cart total after coupon removal [Approve] [Reject] ``` Click **Approve**. The card updates to show it is processing, then updates again once the ticket is dispatched. Click **Reject**, and nothing is created. ## 4. Watch it work A ticket from Slack runs the same way as one from the dashboard or an MCP client. It plans a workflow graph, works in an isolated sandbox against your project's repository, and lands through the same pipeline. See [Alchemist Tickets](/docs/guides/alchemist-tickets) for how that graph runs. In Slack, one message updates in place as the agent works. The channel does not fill up with a message per step. ## 5. Where the result shows up The finished result posts back to the same thread. The ticket also appears in your project's normal **Tickets** list, and in **Work Review** under its originating thread, next to anything dispatched from the dashboard or over MCP. A ticket from Slack is not a second kind of ticket. If the agent needs your input mid-run, for example an unclear business rule or a missing credential, it can ask in the same thread. See [Answering Agent Questions](/docs/guides/alchemist-awaiting-input) for what that looks like. > **Warning:** Slack must hear back from Chipp within a few seconds of a button click. **Approve** and **Reject** acknowledge right away, and the ticket dispatches after. Expect the card to update twice: once to a processing state, then to its final state. ## FAQ **Do I need a separate Slack app for each project?** Yes. Each project's agent connects through its own Slack app, created from Chipp's manifest, the same way any Chipp app connects to Slack. **Who can approve a proposed ticket?** Anyone in a channel where the agent is present can mention it and propose work. Only an owner or editor of the project in Chipp can approve or reject the card. When someone clicks a button, Chipp reads that person's email from their Slack profile and matches it to a Chipp account. If the email does not belong to an owner or editor, or Slack does not share it (common for guests from another workspace in a shared channel), the click is refused and the card stays open for someone who can decide. The same rule covers cards that ask to run a custom action or an integration action. **Does a ticket from Slack cost anything different?** No. It runs under your project's normal ticket budget, like any other ticket. See [Alchemist Budgets and Costs](/docs/guides/alchemist-budgets-and-costs). **Can I also get notified by email?** Yes. Approvals and cross-project proposals can notify by email as well as Slack. See [Cross-Project Proposals](/docs/guides/alchemist-cross-project-proposals) for setup. **Can I dispatch a ticket from Slack without the approval step?** No. The agent always shows the card before it creates a ticket. This stops a stray mention from turning into billed work. ## Next steps For how the workflow graph runs, see [Alchemist Tickets](/docs/guides/alchemist-tickets). To script ticket creation instead of chatting with the agent, see the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide. --- # Alchemist: Clone Your App's Code and Develop Locally Clone your Alchemist-built repository, make changes in Claude Code or Cursor, push to deploy, and debug your live app with the built-in MCP tools. --- Every app you build on the Alchemist platform lives in a real git repository. You own that code, and you can clone it down and work on it directly: fix a sticky issue by hand, explore the codebase in your editor, or run the whole app locally with Claude Code, Cursor, or any tooling you like. Pushing your changes deploys them through the same pipeline the Alchemist agents use. You do not need a GitHub account for any of this. Access goes through a project-scoped credential that you mint and revoke yourself. > **Note:** This guide is about the Alchemist autonomous development platform at build.chipp.ai. If you are looking for the Alchemist copilot inside the Chipp app builder, see the [Alchemist guide](/docs/guides/alchemist). ## 1. Mint a git credential Only the tenant owner can mint credentials. 1. Open your project at build.chipp.ai. 2. Go to the **Deployment** tab → **Git access**. 3. Click **+ Mint credential**. 4. Copy the token (it starts with `alchg_`) immediately. It is shown exactly once; store it in a password manager or your git credential helper. You can list active credentials (with creation and last-used dates) and revoke any of them from the same panel. Revocation takes effect on the very next request. ## 2. Clone your repository The clone URL is shown on the Git access panel. It looks like: ``` https://build.chipp.ai/alchemist-api/git/.git ``` The credential goes in the HTTP password field; the username can be anything. The dashboard's copy-paste command (Overview -> "Work locally") now does the safe thing by default: it stores the token via `git credential approve` scoped to the full clone URL, then clones with a clean URL so the token never lands in `.git/config` or `git remote -v`: ```bash printf 'protocol=https\nhost=build.chipp.ai\npath=alchemist-api/git/.git\nusername=x\npassword=alchg_...\n' | git credential approve \ && git clone -c credential.useHttpPath=true https://x@build.chipp.ai/alchemist-api/git/.git my-app ``` An alternative is `~/.netrc` (file mode 600): ``` machine build.chipp.ai login x password alchg_... ``` Or with your git credential helper (for example the macOS Keychain): ```bash git credential approve <<< " url=https://build.chipp.ai/alchemist-api/git/.git username=x password=alchg_... " ``` Then clone without inline credentials: ```bash git clone https://build.chipp.ai/alchemist-api/git/.git my-app ``` > **Warning:** Working on more than one Alchemist project on the same machine? macOS Keychain (and most git credential helpers) store credentials by **host only**, not by path. Cloning a second project overwrites the first project's saved password for `build.chipp.ai`, and pushes to the first repo start failing with a 404 (a mismatched credential looks identical to "wrong project" by design, so the proxy never reveals which). Store each project's credential explicitly scoped to its full clone URL (`git credential approve` with the exact `url=` shown above, once per project) rather than relying on the helper to disambiguate by host. ## 3. Run the app locally Your repository is a complete, runnable project. From the clone: ```bash ./scripts/setup.sh # first time: toolchain check, deps, local Postgres + Redis, migrations ./scripts/dev.sh --api-port 8000 --port 5173 ``` The repo's `CLAUDE.md` documents the project's conventions, dev login flow, and test commands, so Claude Code and Cursor pick up the house rules automatically. ## 4. Push to deploy Commit and push to the `staging` branch: ```bash git add . git commit -m "Fix the thing by hand" git push origin staging ``` A push to `staging` deploys through the normal Alchemist pipeline, exactly like an agent merge, and shows up in the project's **Deployment** tab. Pushes are coordinated with in-flight agent work: if the platform is mid-merge on your project, your push gets a clear "retry in a moment" message instead of racing it. Three guardrails to know about: - Changes under `.github/workflows/` are rejected at push time (the platform's repo credential deliberately cannot modify CI workflows). - Force-pushing is refused. If your push is rejected because the remote has commits you do not have, run `git fetch origin staging && git merge origin/staging` and push again. - Pushes are capped at 100MB. This comfortably covers ordinary application-code changes; if you hit it, check for an accidentally-committed binary, dataset, or dependency directory rather than something that belongs in the repo. ## 5. Debug the deployed app from your editor Every repository ships with a `.mcp.json` that connects Claude Code (or any MCP client) to the Alchemist MCP server at `https://build.chipp.ai/alchemist-api/api/mcp`, authenticated with an `alch_` key read from the `ALCHEMIST_API_KEY` environment variable. A tenant owner or admin creates that key on the **API Keys** page in the Alchemist tab sidebar (see [API keys](/docs/guides/alchemist-api-keys)); export it with `export ALCHEMIST_API_KEY=alch_...` before you start your client. The `alchg_` git credential from step 1 is a different credential and does not work here. To use your personal Chipp login instead of a key, point the file at Chipp's unified MCP endpoint: ```json { "mcpServers": { "chipp": { "type": "http", "url": "https://build.chipp.ai/mcp" } } } ``` With the unified endpoint there is no key to export. The first tool call opens a browser window for a one-time OAuth approval, then your client holds the session. This works as long as your org is entitled (STUDIO_PRO, ENTERPRISE, or Chipp Executive) and has connected Alchemist Cloud under **Settings → Alchemist Cloud**; see the [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) guide if you would rather use a dedicated tenant-wide key instead of your personal login. Your agent then has these tools against your deployed app, alongside the rest of the Alchemist Cloud catalog: | Tool | What it does | | --- | --- | | `get_project_errors` | Error-level logs from your deployed app (5 minutes to 7 days back, with pattern filtering) | | `get_project_logs` | Full log search: error, warn, and info levels | | `query_database` | Read-only SQL against your app's production database (SELECT only, row-capped, time-limited) | | `get_env_status` | Which required environment variables are configured on the deployment | | `dispatch_ticket`, `list_tickets`, `get_ticket_reports` | Hand work back to the autonomous pipeline | There are no production database credentials to configure, and you should never need any: `query_database` is the only path to production data, and it is read-only by construction. A practical rhythm for hand-fixing an issue: reproduce it with `get_project_errors` or `get_project_logs`, inspect the data with `query_database`, fix and verify locally, then `git push origin staging` to ship it. Anything you would rather not do by hand, send back to the agents with `dispatch_ticket`. ## FAQ **Do I need a GitHub account or seat?** No. The credential is issued by the platform and scoped to your project's repository only. **Can my whole team use one credential?** Credentials are per-project, not per-person, so sharing works, but minting one credential per person means you can revoke one person's access without rotating everyone. **What happens if I leak a token?** Revoke it in **Deployment** → **Git access**. It stops working on the next request. Then mint a fresh one. **Can I push branches other than `staging`?** Yes. Feature branches push fine and do not deploy; only pushes to the base branch trigger a deployment. **Does pushing interfere with Alchemist tickets?** No. Your pushes and agent merges go through the same serialization and are deduplicated by commit, so the same change never deploys twice. **Can I fetch a ticket's own branch, not just `staging`?** Yes, the proxy reaches every branch. See [Rescuing a Stuck Ticket](/docs/guides/alchemist-stuck-ticket-recovery) for the full recovery workflow. --- # Recipes, Feature Packs & the Marketplace Understand the three building blocks of the Alchemist template system: Feature Packs (atomic reusable capabilities), Recipes (curated compositions), and Marketplace Listings (the commercial wrapper for purchasing and licensing them). --- import Callout from "../../../components/docs/Callout.astro"; Alchemist projects are built from composable building blocks. Before you browse the Marketplace or start a new project from a recipe, it helps to understand the vocabulary -- three distinct concepts that appear throughout the platform and the docs. ## The Three Concepts ### Feature Pack A **Feature Pack** is an atomic, reusable capability: a named unit of functionality with its own files, migrations, tests, and agent-guidance notes. Feature Packs are the smallest unit of composition in the Alchemist template system. Examples of Feature Packs: | Pack | What it provides | |------|-----------------| | `core-platform` | Baseline auth (OTP + optional OAuth), JWT session middleware, dashboard shell | | `commerce-catalog` | Server-rendered product catalog pages with Postgres, dynamic sitemap, JSON-LD | | `commerce-cart-checkout` | Session-aware cart, Stripe Checkout integration, orders/inventory | | `cms-content` | Multi-client editorial workflow and content model | | `lead-contact-capture` | Contact-form + newsletter capture with transactional email | | `seo-social-metadata` | Open Graph, canonical URL, sitemap/robots.txt | Feature Packs declare their dependencies on each other, so the composition engine can resolve the full dependency graph before a single file is written. ### Recipe A **Recipe** is a versioned composition of Feature Packs, bundled with sensible defaults, configuration knobs, workflow instructions, agent guidance, UI conventions, and seller-supplied assets. Starting a project from a Recipe gives you a coherent, tested stack rather than assembling packs by hand. Eight first-party Recipes are available today: | Recipe | Best for | |--------|----------| | **Web App** (`web-app`) | Full-stack SaaS starter -- Hono API + Svelte 5 SPA, auth, org model, design system | | **Headless API** (`api`) | The web app with its built-in API switched on: API keys and monetized `/api/v1` routes | | **MCP Server** (`mcp-server`) | The web app with its built-in MCP server switched on: `/api/mcp` with OAuth 2.1 and monetized tools | | **Agent Storefront** (`agent-storefront`) | Sell access to an existing Chipp agent -- landing page + app container | | **Commerce Storefront** (`commerce-storefront`) | SEO e-commerce -- server-rendered catalog, cart, Stripe Checkout, seller dashboard | | **Agency CMS** (`agency-cms`) | Multi-client editorial CMS -- many client sites from one app, editorial workflow, SEO | | **Command Center** (`command-center`) | Internal business dashboard -- KPIs, data, and activity in one view | | **Landing Page** (`landing-page`) | Funded-startup-quality marketing site -- hero, social proof, lead capture, SEO | > **Note:** First-party Recipes are free with any plan. Third-party Recipes and > Feature Packs from verified sellers are listed in the Marketplace browse > view. ### Marketplace Listing A **Marketplace Listing** is the commercial wrapper around a Recipe, a Feature Pack, or a bundle. A Listing is what you browse, purchase, and license. It contains: - The published version of the Recipe or Feature Pack - Pricing (one-time license fee + optional Maintenance subscription) - Seller identity and support contact - Changelog, compatibility notes, and a demo/screenshots - Licensing terms (one project per license, source-visible, customizable) --- ## How They Fit Together ``` Feature Pack A + Feature Pack B + Feature Pack C \ | / \ | / RECIPE (versioned composition) | Marketplace Listing (priced, published) | License (one project, perpetual use of that version) | optional Maintenance Subscription (updates, support, reconciliation) ``` You can think of it as layers: 1. **Feature Packs** are Lego bricks -- small, tested, reusable. 2. **Recipes** are curated Lego sets -- a complete build plan with a clear outcome. 3. **Marketplace Listings** are the store shelf -- priced, versioned, with seller info and licensing terms attached. 4. A **License** grants one project the perpetual right to use and customize a specific version's source code. 5. A **Maintenance Subscription** extends that right to receive compatible updates, AI-assisted reconciliation, security notices, and seller support. --- ## Quick-Start Paths **Starting a new project from a Recipe** -- open the Marketplace in the Alchemist dashboard, pick a card under "Start a new project from a first-party recipe," inspect the included Feature Packs and configuration knobs in the new-project form, confirm the license cost, and create. The platform provisions the project using the canonical recipe composition path. [Detailed walkthrough](/docs/guides/alchemist-marketplace-browse-purchase) **Adding a Feature Pack to an existing project** -- open your project's Marketplace tab (or the standalone Marketplace), find the pack, run the install analysis, review the planned file changes and any conflicts, and apply. AI reconciliation handles merge conflicts in modified files. [Detailed walkthrough](/docs/guides/alchemist-marketplace-install) **Publishing your own Recipe or Pack** -- see the [Seller Guide](/docs/guides/alchemist-marketplace-seller-guide) for how to package, price, publish, and support your listing. --- ## Frequently Asked Questions See the [Marketplace FAQ](/docs/guides/alchemist-marketplace-faq) for answers to common questions about licensing, maintenance, pricing, and the seller experience. --- # Marketplace: Browse, Purchase & Create a Project How to discover Recipes and Feature Packs in the Alchemist Marketplace, understand pricing and licensing before purchase, and create a new project from a first-party or third-party Recipe. --- import Callout from "../../../components/docs/Callout.astro"; The Alchemist Marketplace is the canonical discovery surface for Recipes and Feature Packs -- first-party templates from Chipp and third-party listings from verified sellers. You can reach it from two places: - **Primary nav**: the **Recipes & Marketplace** item in the Alchemist sidebar is always visible, no project context required. - **Project Marketplace tab**: every project has a **Marketplace** tab where you purchase or redeem a listing into that project. ## Browsing and Filtering The browse view shows the first-party Recipes, a **Browse by type** row, **Featured** and **Recently updated** listings, and **All listings**. Use the filters above **All listings** to narrow results: | Filter | What it does | |--------|-------------| | **Search by name, use case, or industry** | Text match against listing titles, summaries, and descriptions | | **Type** | Recipe / Feature Pack / Bundle | | **Seller** | Any seller, or one specific seller (verified sellers are marked) | | **Verified publisher only** | Listings from sellers Chipp has marked as verified | | **Ongoing maintenance offered** | Listings whose latest version offers an annual Maintenance plan | > **Note:** When nothing matches, the browse view shows "No listings match your > filters." with a **Clear filters** button. The browse view is never a > blank page. ## Reading a Listing Detail Page Before purchasing, every listing detail page shows: **What you get** - Plain-language summary and description - Full list of included packs and their descriptions, with the packs each one composes - Seller name (linked to the seller profile) and a verified badge where it applies **Versioning and compatibility** - Current version number, publish date, and changelog - Compatibility declaration, or "No compatibility constraints declared." **Licensing terms (read these before you buy)** - **Source-visible, customizable**: you receive the actual source files and can modify them freely inside your project. - **One project per license**: the license is bound to the single project you purchase it into. Using the same code in a second project requires a separate license. - **Perpetual use of the purchased version**: your license never expires. Even if you cancel Maintenance or the seller unpublishes the listing, your right to use and modify the installed version in that project is permanent. **Pricing and Maintenance** - **One-time license** price - **First year of maintenance** - **Ongoing maintenance** price - Plain statement of what happens when Maintenance ends > **Warning:** Pricing disclosures on every listing are intentionally explicit: the > one-time price, the Maintenance renewal price (if any), and the > post-Maintenance state are each shown separately. The listing detail page > has no purchase button: to buy, open the listing from a project's > **Marketplace** tab so the license binds to that project. ## Starting a Project from a Recipe **Step 1 -- Pick a Recipe** Click a first-party Recipe card on the **Recipes & Marketplace** page (each card reads "Create project from ..."), or open **New project** and pick a card in the template grid. First-party Recipes are free with any plan. **Step 2 -- Inspect the Recipe** When the selected template is a Recipe, the dialog shows: - The build profile (full-stack or headless) - **Included Feature Packs** - **Configuration knobs you'll set next** (for example brand name or checkout currency) - The license cost: "First-party recipes carry no separate marketplace license fee." **Step 3 -- Describe the project and create it** Name the project and describe what you're building. The knobs are read-only in the dialog: you set them with the Alchemist during the scoping conversation that follows. The platform records the recipe composition as provenance on the new project. > **Note:** Project creation from a Recipe uses exactly the same infrastructure path > as a blank project -- the only difference is that the recipe composition > is pre-applied rather than empty. There is no alternate code path. ## What Happens After Creation After the project is created, its **Marketplace** tab lists the published catalog (with **Purchase** and **Redeem** on each listing you can buy) and **Licenses on this project**, where you install packs and manage Maintenance. ## Pricing: Free and Paid Listings **Free listings** -- first-party Recipes are free with any plan and carry no separate license fee. If Chipp gives you a coupon or grant code, enter it in **Coupon / grant code** on the project's **Marketplace** tab and click **Redeem**. See [Coupons and Alpha Grants](/docs/guides/alchemist-marketplace-maintenance#coupons-and-alpha-grants) for how grants work. **Paid listings** -- open the project's **Marketplace** tab and click **Purchase** on the listing. Payment runs through Stripe Checkout, and the license is bound to that project on payment success. You pay the **seller**: the charge is made on the seller's own Stripe account, the seller is the merchant of record, and your receipt and card statement show the seller. Chipp's marketplace fee is included in the listed price. A listing whose seller has not finished connecting a Stripe account cannot be purchased yet. **Refunds** -- the seller is the merchant of record, so refunds are made on the seller's Stripe account. Ask the seller through their profile, or contact Chipp support and we will route the request. A listing carries no additional guarantee beyond what its detail page states. --- # Alchemist: Rescuing a Stuck Ticket Fetch a stuck ticket's agent branch through the git proxy, fix it in Claude Code or Cursor, and land it into staging yourself. --- Every ticket does its work on its own branch, `agent/`, and only reaches `staging` once it lands. Most tickets land on their own. When one does not, a land step that could not complete, or a run you cancelled mid-way, the work is not lost. It sits on that branch. You can fetch it, finish it, and land it yourself. > **Note:** This guide assumes you already have a git credential and a local clone. If you do not, start with [Clone Your App's Code and Develop Locally](/docs/guides/alchemist-local-development). ## 1. Find the branch name Open the stuck ticket's detail page. A ticket that could not land names its own branch in two places: the question it is waiting on you to answer, and the failure reason underneath it. Both read something like: ``` Implementation on branch agent/9f0114b6-fe05-4d41-8bf2-04962bc2ee94 looks complete, but it was never landed. Approve a land continuation, or land it manually and reply once it's merged. ``` The branch is always `agent/`, the same job id shown in the ticket's own detail URL. ## 2. Fetch it through the git proxy The same [git proxy](/docs/guides/alchemist-local-development) that clones and pushes `staging` reaches every branch in the repository, not just the default one. From your existing clone: ```bash git fetch origin git branch -r | grep agent/ ``` ``` origin/agent/9f0114b6-fe05-4d41-8bf2-04962bc2ee94 ``` Check out the one you need: ```bash git checkout -b recovery agent/9f0114b6-fe05-4d41-8bf2-04962bc2ee94 ``` You are now on the exact state where the ticket stopped. `git log --oneline -5` shows the commits the agent made before it parked. ## 3. Fix it, in Claude Code, Cursor, or anything else Work in the checked-out branch the way you normally would. The repo's own `CLAUDE.md` still applies, so an editor that reads project instructions picks up the same conventions the agent was following. ## 4. Land it into staging Merge your branch into `staging` locally, then push through the proxy: ```bash git fetch origin staging git checkout staging git merge origin/staging # picks up anything that landed since you last fetched git merge recovery # brings in the fix git push origin staging ``` Pushing to `staging` deploys through the normal pipeline, the same as an agent's own merge. If another merge is in progress, the proxy asks you to retry, safe to do immediately. ## 5. Close the ticket out If the ticket is still waiting on a reply, answer it (from the ticket page, or `reply_to_ticket` over [MCP](/docs/guides/alchemist-mcp-server)) noting that you merged it yourself. That is the reply the question itself is asking for, and it is what moves the ticket out of "waiting." ## FAQ **Do I need special access to fetch an agent branch?** No. The same project-scoped credential that clones and pushes `staging` reaches every branch, agent branches included. **What if I check out the wrong branch by mistake?** Nothing happens until you push. Fetching and checking out is read-only. **Does this only work for stuck tickets?** No, the proxy has no concept of "stuck." This is simply the most common reason to reach for a branch other than `staging`. **Can two tickets be stuck on the same branch at once?** No. Each ticket gets its own `agent/` branch, so recovering one never touches another's work. ## Next steps For how a ticket's branch and land step normally work, see [Alchemist Tickets](/docs/guides/alchemist-tickets). For the full local development setup this guide builds on, see [Clone Your App's Code and Develop Locally](/docs/guides/alchemist-local-development). --- # Marketplace: Install into an Existing Project How to discover, analyze, and apply Feature Packs and Recipe updates to an already-running Alchemist project, including conflict detection, AI-assisted reconciliation, versioning, and compatibility. --- import Callout from "../../../components/docs/Callout.astro"; If your project already exists and you want to add a Feature Pack or pull in a Recipe update, you use the post-creation install surface rather than recreating the project from scratch. This guide covers how to discover compatible add-ons, run the install analysis, apply changes, and understand how versioning and conflict reconciliation work. ## Finding Add-Ons for Your Project ### From the project Marketplace tab Every Alchemist project has a **Marketplace** tab in the sidebar. Opening it shows: - **Catalog** -- the published listings, each with its one-time price, annual Maintenance price, and version. Click **Purchase** to buy a listing into this project through Stripe Checkout, or enter a **Coupon / grant code** and click **Redeem**. A listing this project already holds shows "This project already has an active license for this listing." - **Licenses on this project** -- each license with its Maintenance state and the packs it includes. This is where you install and update packs. ### From the standalone Marketplace You can also browse the full catalog under **Recipes & Marketplace** in the sidebar. The listing detail page shows each listing's declared compatibility. To purchase, open the listing from the project's **Marketplace** tab so the license binds to that project. > **Note:** Compatibility checking is based on the pack dependency declarations in the > catalog. The preview step (below) provides a more precise report against > your actual project files before anything is written. ## Previewing an Install Expand a license under **Licenses on this project** and click **Preview install** (or **Preview update** for a pack that is already installed) on a pack. Before any files are written, the preview: 1. **Checks dependencies and conflicts** -- compares the pack's declared dependencies and conflicts against the packs already installed in your project. 2. **Compares files** -- checks each file the pack writes against what already exists in your project. 3. **Produces a change plan** -- the number of file changes, and whether the change is a clean apply or needs AI reconciliation. 4. **Lists what else is needed** -- the changelog for the incoming version and any secrets the pack requires. The preview is read-only and non-destructive. You can run it as many times as you like. > **Warning:** Updating to a newer version needs active Maintenance on the license. If > Maintenance has lapsed or was never bought, **Apply** fails with a > Maintenance message and nothing is written. ## Understanding the Change Plan The analysis classifies each file the pack writes: | Category | What it means | |----------|--------------| | **Add** | File does not exist in your project yet -- safe to write directly | | **Identical** | File already matches what the pack would write -- no change | | **Update** | File still matches what the installed pack version wrote -- the pack's own version-to-version change applies directly | | **Overlap** | File differs from both the incoming version and what the pack wrote before -- you (or an agent) changed it, so it is never overwritten silently | If any file overlaps, the plan is not a clean apply and the platform routes the change to AI reconciliation. ## Applying the Changes After reviewing the preview: - **Apply** (clean apply) commits the pack's files directly to your project's repo and records the installation as provenance on the project. - **Apply (via AI reconciliation)** (your files have drifted) dispatches an Alchemist ticket instead of overwriting anything. The agent merges your changes with the incoming pack version. Your current version stays live until that ticket lands. Any database migrations included in the pack ship with the commit and run on the next deploy. ## Versioning and Compatibility ### How versions work Each Marketplace Listing publishes a version number following semantic versioning conventions (e.g. `1.2.0`). Packs declare the range of versions of their dependencies they are tested against. When you install a pack, the version you receive is recorded as provenance on your project. ### Compatibility declarations A listing's detail page shows: - **Current version** and publish date - **Changelog** -- a human-readable description of what changed - **Compatibility** -- the constraints the listing declares, or "No compatibility constraints declared." ### Forks and divergence When an AI reconciliation ticket lands, the resulting file is a fork: your project's copy now diverges from the canonical pack source. This is expected and intentional -- you own the source, and customization is a first-class use case. If a future pack update modifies the same file again, the preview flags it as an overlap and the update routes to AI reconciliation again, which incorporates both your prior divergence and the new upstream changes. ### Staying up to date With active Maintenance, you can preview and apply newer compatible versions from **Licenses on this project**, and changelogs show on the listing detail page and in the preview. Without active Maintenance, you keep the installed source and the perpetual right to use the version you purchased, but you stop receiving new compatible updates, AI-assisted reconciliation, and security/compatibility notices for that listing until Maintenance is renewed. See [Maintenance Subscriptions](/docs/guides/alchemist-marketplace-maintenance) for details on what Maintenance covers and how cancellation works. ## Security, Review, and Support Expectations ### Security posture of published packs A seller publishes a pack, Recipe, or bundle version directly from **Sell Recipes**. There is no automated security scan or Chipp review step before a pack, Recipe, or bundle version is listed, and a published version is frozen: it cannot be changed after publishing. > **Warning:** A listing in the Marketplace is not a guarantee that a pack is free of > vulnerabilities. Treat installed pack source with the same > care as any third-party code: read the files, run your own tests, and > report issues to the seller and to Chipp's security contact. ### Seller support Each listing's detail page links to the seller's profile. Support for a listing is provided by the seller while Maintenance is active. For issues with a specific pack, contact the seller directly. For platform-level concerns (billing, entitlement, account), use Chipp's support. Sellers are not obligated to provide support beyond what is stated in their listing. Active Maintenance subscribers are entitled to the level of support the seller declares in the Maintenance terms on the listing. ### Verified publisher badge Listings from sellers Chipp has marked as verified display a **verified** badge. It does not constitute a warranty or guarantee. ### Reporting security issues If you discover a security vulnerability in a published pack: 1. Contact the seller through the channel on their profile page. 2. Also report to Chipp via the security contact in the platform footer. 3. Do not publish the vulnerability publicly before the seller has had a reasonable opportunity to issue a patch (coordinated disclosure). Chipp may delist or quarantine a listing while a reported vulnerability is being addressed. --- # Marketplace: Maintenance Subscriptions, Updates & Perpetual Rights Understand Maintenance subscriptions -- what they cover, how renewal and cancellation work, why perpetual version rights survive cancellation, and how coupons and 100%-off grants work. --- import Callout from "../../../components/docs/Callout.astro"; A Marketplace purchase gives you two distinct things: a **License** and an optional **Maintenance subscription**. These are intentionally separate so you understand exactly what you own and what is ongoing. ## What a License Gives You A **License** grants one project the perpetual right to use and modify a specific version's source code. This right never expires, regardless of what happens to the Maintenance subscription, the seller's account, or the listing's published status. Specifically, your license guarantees: - You received the actual source files at the installed version. - You can modify those files freely within your project. - The right to use and modify that version in that project is **permanent**. - If you cancel Maintenance, unpublish occurs, or the seller stops operating, your installed source and perpetual use rights are unaffected. > **Note:** Licenses are project-bound. Using the same pack in a second project requires > a second license at the same price. One license = one project. ## What Maintenance Gives You A **Maintenance subscription** is optional and adds: | What you get | Notes | |-------------|-------| | **Compatible updates** | Access to newer pack versions through the Marketplace tab | | **AI-assisted reconciliation** | When an update has conflicts with your modifications, the reconciler is dispatched | | **Security notices** | Notifications when a security or compatibility issue is found in an installed pack | | **Compatibility notices** | Alerts when a dependency or runtime change affects your version | | **Seller support** | Access to the seller's stated support channel during the active period | Maintenance is priced as an annual subscription. The default term is one year. Some listings include first-year Maintenance in the one-time purchase price; others price it separately. The listing detail page shows both amounts explicitly before you purchase. ## Renewal and Cancellation ### Auto-renewal Maintenance auto-renews once a year by default. The renewal date is shown on the project's **Marketplace** tab, under **Licenses on this project**. - **Reminder.** About 7 days before the renewal date, everyone on the buyer workspace gets one email with the amount and the date. - **The charge.** On the renewal date we charge the listing's annual Maintenance price to the **card you paid with at purchase**. That card is saved on the seller's Stripe account, because the seller is the merchant of record: the renewal is a charge by the seller, the same as the purchase. Chipp's marketplace fee is deducted from that charge; it is not an extra cost to you. A successful charge extends Maintenance by one year. - **No saved card, or a declined card.** We try again 1 day later and 3 days later. If all three attempts fail, Maintenance lapses and you get one email saying so. Your license and installed source are not affected, and you can renew by hand at any time. - **Free Maintenance.** A listing with a $0 Maintenance price renews automatically with no charge. ### Cancelling Maintenance To cancel auto-renewal, open the project's **Marketplace** tab, expand the license under **Licenses on this project**, and click **Cancel auto-renew**. Your Maintenance access continues through the already-paid-for period (the `maintenance_through` date). After that date: - Update access, reconciliation, notices, and support access lapse. - **Your license, installed source, and perpetual use rights are completely unaffected.** Cancellation touches only the Maintenance subscription record, never the entitlement. > **Warning:** Cancellation is not the same as losing your code. The installed source files > remain in your project exactly as they were. The only thing that changes is > access to future updates and support. ### Renewing by hand after a cancel Cancelling auto-renew never locks you out of renewing. **Renew maintenance** stays on the license after you cancel, before and after the end date, and after an auto-renew charge lapses. - **Renew maintenance** opens a checkout for one more year. If your current term has not ended, the new year starts at the end of it, so you lose no paid time. If it already ended, the new year starts today. - Renewing by hand does **not** turn auto-renew back on. You pay for one year and nothing is charged next year unless you choose to. - **Turn auto-renew back on** appears after you cancel. It charges nothing now; the card saved at purchase is charged on the renewal date. If the term already ended, the charge runs within the hour. ### What "perpetual version rights" means in practice When Maintenance ends (by cancellation, expiry, or seller account closure): - Your project keeps every file installed up to that point. - Those files are yours to modify, deploy, and maintain. - You cannot pull future pack updates without an active Maintenance subscription (or purchasing a new license for the updated version). - The seller's ability to support, patch, or update their listing does not affect your right to use your installed copy. ## Coupons and Alpha Grants ### How coupons work Coupons are issued by Chipp and redeemed instead of paying at Stripe checkout. A coupon can be a percentage discount or a fixed-amount discount. It may apply to one specific listing or to any listing. Coupons have optional expiry dates and redemption limits. To redeem a coupon: 1. Open the project's **Marketplace** tab. 2. Find the listing in the **Catalog**. 3. Enter the code in the **Coupon / grant code** field next to it. 4. Click **Redeem**. The project receives a full license. ### First-party Recipes are free The first-party Recipes are picked in the **New project** dialog and are labeled "Free with any plan". They carry no separate marketplace license fee, so there is nothing to purchase or redeem and no coupon code is needed. ### 100%-off grants A 100%-off grant is a coupon with a 100% discount. You redeem it the same way as any other coupon, from the project's **Marketplace** tab. The project receives a full license (perpetual use rights) at no cost, with the same one-year Maintenance term as a paid purchase. Sellers cannot issue coupon codes themselves; coupons are created by Chipp. ## Managing Your Subscriptions All of a project's licenses and their Maintenance state are listed on the project's **Marketplace** tab, under **Licenses on this project**. Expand a license to: - See the Maintenance state and renewal date (or the date updates end). - Click **Cancel auto-renew** (access continues through the paid period). - Click **Renew maintenance** to pay for one more year by hand. It is there whenever auto-renew is off, including after a cancel and after the term ended. - Click **Turn auto-renew back on** after a cancel. - Preview and apply the packs in the license. The preview shows the version's changelog. Licenses are managed per project; there is no workspace-wide Marketplace billing panel. ## Related guides - [Recipes, Feature Packs & the Marketplace](/docs/guides/alchemist-recipes-overview) -- the vocabulary and mental model behind everything above. - [Marketplace: Browse, Purchase & Create a Project](/docs/guides/alchemist-marketplace-browse-purchase) -- how to read a listing's price and Maintenance terms. - [Marketplace: Install into an Existing Project](/docs/guides/alchemist-marketplace-install) -- how Maintenance gates which updates you can apply. - [Marketplace FAQ](/docs/guides/alchemist-marketplace-faq) -- concrete answers to common licensing and Maintenance questions. --- # Marketplace Seller Guide: Publish Recipes & Feature Packs Everything a seller needs to package, price, publish, version, and support a Recipe or Feature Pack in the Alchemist Marketplace. Includes marketplace economics, the configurable platform fee, how Stripe pays sellers directly, and a worked example. --- import Callout from "../../../components/docs/Callout.astro"; The Alchemist Marketplace is open to third-party sellers. If you have built a reusable capability -- a Feature Pack, a full Recipe, or a thematic bundle -- you can publish it, set your price, and get paid directly to your own Stripe account on each purchase. ## Getting Started: Seller Onboarding To sell on the Marketplace: 1. **Open the seller page** -- click **Sell Recipes** in the Alchemist sidebar, or **Sell a Recipe** on the **Recipes & Marketplace** page. 2. **Create your seller profile** -- under **Become a creator**, enter a **Display name** and an optional **Bio**, then click **Create seller profile**. Each organization can have one seller profile. 3. You can now create draft listings. The **verified** badge is set by Chipp; it is not part of self-serve onboarding. 4. **Connect your Stripe account.** Before you publish any paid listing, you must connect a Stripe account that can accept charges. Buyers pay you directly on that account. A paid listing cannot be published (or bought) until the account is connected and can accept charges. > **Note:** Seller profiles are public and linked from every listing you publish. > Buyers see your display name, a short bio, published listing count, and > your support-contact channel. ## Packaging a Recipe or Feature Pack ### Pack manifest Every Feature Pack is defined by a manifest that declares: - `packId` -- unique identifier (e.g. `supply-chain-visibility`) - `name` -- human-readable display name - `description` -- what the pack does and what it provides - `version` -- semantic version of this pack release - `dependencies` -- other pack IDs (and version ranges) this pack requires - `configSchema` -- the configuration knobs buyers can set at install time - `files` -- the source files the pack contributes - `migrations` -- database migration scripts (if any) - `agentGuidance` -- notes the Alchemist agent uses when working inside a project that has this pack installed ### Recipe manifest A Recipe manifest wraps one or more Feature Packs into a cohesive composition: - `recipeKey` -- unique key (e.g. `supply-chain-ops`) - `name` and `description` -- what the recipe builds - `version` -- semantic version - `packs` -- ordered list of pack IDs this recipe composes - `configSchema` -- top-level knobs promoted from underlying packs - `defaults` -- default values for knobs - `workflows` -- named workflow templates bundled with this recipe - `prompts` -- agent-prompt templates - `assets` -- screenshots, demo links, and branding for the listing ### Dependencies and version ranges Declare dependencies conservatively. If your pack only works with specific versions of another pack, express that as a version range (e.g. `>=1.0.0 <2.0.0`). Overly narrow ranges block buyers from using your pack alongside newer dependencies; overly broad ranges may expose your pack to breaking changes. ## Writing the Listing In the seller dashboard, a listing and each of its versions take these fields: | Field | Where | Notes | |-------|-------|-------| | Type | Listing | `pack`, `recipe`, or `bundle` | | Title | Listing | Short, descriptive (max 200 chars) | | Summary | Listing | Plain-language "what this builds" | | Manifest ids | Listing | Comma-separated pack or recipe ids this listing sells | | Version | Version | Version label for this release | | One-time price (cents) | Version | In USD cents; 0 for a free listing | | Maintenance/yr (cents) | Version | 0 if you do not offer Maintenance | | Changelog | Version | What changed in this version | ## Setting Prices ### One-time license price This is what buyers pay at purchase to receive the source code and perpetual use rights. You set this in your seller dashboard when you create a draft version. Once you have recorded a price recommendation for the listing, the price must fall within 50%-200% of the recommended one-time price, or the server rejects the version. ### Maintenance subscription price Maintenance is priced annually by the seller. You may include first-year Maintenance in the one-time price (common for premium listings) or price it separately. Buyers who cancel Maintenance keep their source and license. ### Pricing recommendations Under **Price recommendation**, enter **Estimated effort (hours)**, **Complexity**, **Dependencies**, **Included workflows**, and **Support level**, then click **Compute recommendation**. The result is a recommended one-time price and annual Maintenance price, with the reasoning shown. When comparable listing prices are supplied, they are blended in at 30%. You set your own price, within the 50%-200% band described above. > **Note:** Free listings (price = $0) are fully supported. Sellers use free listings > for open-source packs, promotional tiers, or community contributions. ## Marketplace Economics ### Platform fee Chipp charges a **platform fee on each transaction**. The fee is configurable and currently set at **30%** of the gross purchase price (3000 basis points). The fee is: - Applied at transaction time and snapshotted to the transaction record. A later fee change never retroactively alters a historical transaction. - Deducted at charge time: Chipp's fee is taken out of the charge on your Stripe account as an application fee, so it never reaches your balance. - Visible: the **Sales ledger** on your seller dashboard lists each sale with your net amount, its status, and the date. - Per-listing overridable: Chipp may negotiate a different fee rate for specific listings or programs (e.g. launch promotions, verified publisher programs). Any override is applied per-listing and documented on the transaction record. ### How you get paid **Your net = gross purchase price - platform fee** At the default 30% fee: a $100 listing purchase results in a $30 platform fee and **$70 for you**. Every pack, recipe, bundle, and Maintenance sale is charged **on your own Stripe account** (a Stripe Connect direct charge): - **Stripe pays you directly.** The charge lands in your Stripe balance, and Stripe pays it out to your bank on your normal Stripe payout schedule. Chipp never holds your money and never runs a transfer to you. - **You are the merchant of record** for your sales. The buyer's card statement and receipt show your Stripe account. - **Chipp's fee is deducted at charge time** as an application fee on the charge. Your Stripe dashboard shows the gross charge and the fee. - **Refunds and disputes are handled on your Stripe account.** A refund comes out of your Stripe balance. When a sale is refunded, Chipp returns its fee in proportion to the amount refunded, whether the refund was made by Chipp support or by you from your Stripe dashboard. On a dispute, Stripe's normal dispute process and fees apply to your account. Each sale appears in your **Sales ledger** as **paid by Stripe**, with any refund shown on the same row. | Sale | How you are paid | |------|------------------| | Pack, recipe, or bundle license | Charged on your Stripe account; Stripe pays you. | | Maintenance renewal (by hand or auto-renew) | Charged on your Stripe account with the buyer's card saved there; Stripe pays you. | | Whole-project listing | Inside the buyer's payment to Chipp (the buyer also starts a Chipp plan in the same checkout). Stripe sends your share to your connected Stripe account when the buyer pays. | > **Warning:** The 30% figure is the current configurable default. Chipp may adjust the > platform fee rate over time, with advance notice to sellers. Any adjustment > applies only to transactions after the effective date; historical > transactions retain their snapshotted fee. Review the seller agreement for > current terms. ### Maintenance revenue Maintenance subscription renewals follow the same fee structure as the initial purchase. Auto-renew charges the card the buyer saved on your Stripe account at purchase, on the renewal date; buyers get a reminder email about 7 days before. A buyer who cancelled auto-renew can still renew by hand, and each renewal is its own sale on your Stripe account. If your Stripe account cannot accept charges on the renewal date, the renewal does not go through. ### Coupons and grants Coupons are issued by Chipp. A coupon must cover the **full** price: a redemption charges nothing, so neither Chipp nor you receives payment, and the buyer receives a full license and the included Maintenance year. Chipp may separately compensate sellers for grant-covered sales under program agreements. ## Versioning and Updates ### Releasing a new version To release a new version of an existing listing: 1. Select the listing and, under **New draft version**, enter the new **Version**, prices, and a **Changelog** describing what changed. Click **Create draft version**. 2. Click **Publish (freezes forever)** on the draft. A published version can never be edited; ship another version to change anything. Existing buyers see the new version in their project's Marketplace tab only if they have an active Maintenance subscription (or if the update is a free patch within their licensed version range, as declared in your compatibility notes). ### Deprecating a listing The seller dashboard has no deprecate or unlist control today. Contact Chipp support to take a listing off sale. Removing a listing from sale never revokes existing licenses: buyers keep their perpetual rights and installed source. ### Version branching and forks If you need to maintain an older major version alongside a newer one (e.g. for buyers who cannot migrate), you can publish parallel listings at different version branches. Label them clearly in the display name and changelog. ## Review and Security Requirements ### Submission review A draft listing has a **Submit for review** button, which moves it to the `in_review` status. Publishing a version is done by you, from the seller dashboard, and is not blocked on a Chipp review step for pack, recipe, or bundle listings. Full-project listings must pass automatic checks before they publish (source ownership, payout readiness, no committed credentials, no untransferable add-on licenses). You are responsible for the security and correctness of what you publish. ### Security disclosures If a vulnerability is discovered in your published pack: 1. You will be notified by Chipp's security team. 2. You are expected to issue a patched version within a reasonable timeframe (severity-dependent; critical issues may require a faster response). 3. Chipp may temporarily delist the affected version while the patch is in review. 4. Buyers with active Maintenance are notified of the security issue and the availability of the patched version. ### Content and licensing compliance You may only publish packs you have the right to distribute. Your listing must not include: - Code from open-source projects whose licenses are incompatible with commercial redistribution (check your dependencies carefully). - Hardcoded secrets, API keys, or customer data of any kind. - Content that violates Chipp's acceptable-use policy. ## Worked Example: Supply-Chain Visibility Pack The following is a representative example of how a seller might structure a domain-specific Feature Pack. All details are illustrative and contain no private customer data. **Pack: `supply-chain-visibility`** Imagine you have built an inventory-tracking and supplier-status dashboard used in your own projects. To turn it into a sellable pack: **Manifest excerpt:** ```json { "packId": "supply-chain-visibility", "name": "Supply-Chain Visibility Dashboard", "version": "1.0.0", "description": "Real-time supplier status, inventory levels, and shipment tracking for e-commerce and manufacturing projects.", "dependencies": [ { "packId": "commerce-catalog", "versionRange": ">=1.0.0 <2.0.0" }, { "packId": "core-platform", "versionRange": ">=1.0.0" } ], "configSchema": [ { "key": "defaultCurrency", "type": "string", "default": "USD", "label": "Default currency" }, { "key": "lowStockThreshold", "type": "number", "default": 10, "label": "Low-stock alert threshold (units)" } ] } ``` **What the pack contributes:** - A `/admin/supply-chain` route with a real-time dashboard (WebSocket-fed inventory updates, supplier status tiles, shipment ETA table). - A `supply_chain_events` Postgres table and a migration script to create it. - A Deno API route at `/api/supply-chain/events` (stream endpoint). - Agent guidance notes explaining the data model so the Alchemist agent can write queries and modifications correctly. **Pricing:** - One-time license: $149 - First-year Maintenance included, annual renewal: $49/year - At 30% platform fee: you receive $104.30 on the first purchase and $34.30 on each annual renewal, paid by Stripe to your Stripe account. **What sellers must NOT include in the manifest or source files:** - Real supplier names, purchase orders, customer data, or any non-synthetic test fixtures. - Hardcoded API keys or credentials. - References to internal proprietary systems by their real names. This supply-chain example is structural only -- distinct supplier status entities, inventory tracking, shipment ETA -- and exposes no private details from any real customer's data. ## Related guides - [Recipes, Feature Packs & the Marketplace](/docs/guides/alchemist-recipes-overview) -- the vocabulary and mental model every seller should share with buyers. - [Marketplace: Browse, Purchase & Create a Project](/docs/guides/alchemist-marketplace-browse-purchase) -- the buyer-side experience your listing will appear in. - [Marketplace: Maintenance Subscriptions, Updates & Perpetual Rights](/docs/guides/alchemist-marketplace-maintenance) -- what buyers get from the Maintenance price you set. - [Marketplace FAQ](/docs/guides/alchemist-marketplace-faq) -- common seller and licensing questions answered concretely. --- # Marketplace FAQ Answers to common questions about Recipes, Feature Packs, licensing, Maintenance subscriptions, pricing, the seller experience, and platform security. --- import Callout from "../../../components/docs/Callout.astro"; ## Concepts ### What is the difference between a Feature Pack, a Recipe, and a Marketplace Listing? - A **Feature Pack** is an atomic reusable capability: a named unit of functionality with its own source files, migrations, tests, and agent guidance. Think of it as a Lego brick. - A **Recipe** is a versioned composition of Feature Packs bundled with sensible defaults, configuration knobs, workflows, and seller assets. Think of it as a curated Lego set with a clear outcome ("this builds a commerce storefront"). - A **Marketplace Listing** is the commercial wrapper around a Recipe or Pack: it adds a price, a seller, a changelog, compatibility declarations, and licensing terms. A Listing is what you browse, purchase, and license. ### Can I use a Recipe without going through the Marketplace? The first-party Recipes are available directly from the **New project** dialog with no separate purchase step. They are labeled "Free with any plan" and carry no separate marketplace license fee. Third-party Recipes must be licensed through the Marketplace, from a project's **Marketplace** tab. --- ## Licensing ### What exactly does a license give me? A license grants one specific project the perpetual right to use and modify a specific version's source code. The key words are: - **One project** -- you name the project at purchase. Using the same code in a second project requires a second license. - **Perpetual** -- the right never expires, regardless of whether you have an active Maintenance subscription, whether the listing is still published, or whether the seller's account is active. - **Source-visible** -- you receive the actual source files and can read, audit, and modify them freely. - **Customizable** -- you can change any file in the installed pack to fit your project's needs. ### Can I use the same license across multiple projects? No. One license = one project. If you need the same pack in two projects, purchase two licenses. The project is recorded at purchase time and cannot be changed afterward. ### What happens to my license if the seller stops operating? Nothing changes for you. The license and installed source are permanent. The seller's account state does not affect your right to use the installed version in your project. You would lose access to seller support and future updates, but not to any code you already have. ### Can I fork the installed source and build on top of it? Yes. Source-visible customization is a first-class use case. You can modify any installed file, add your own files, and evolve the code however you need within your project. Forked files are flagged in the install analysis so the reconciler knows to merge your changes when you apply future updates. ### Can I transfer a license to a different project? License transfers are not currently supported. The license is permanently bound to the project named at purchase. If you need to move the work to a different project, you would need to create a new project and purchase a new license. --- ## Maintenance ### What does Maintenance give me that the license doesn't? A Maintenance subscription adds: - Access to newer versions of the installed pack through the Marketplace tab - AI-assisted reconciliation when an update conflicts with your modifications - Security and compatibility notices - Seller support access (at the level the seller declares in their listing) The license alone gives you perpetual use of the installed version. Maintenance gives you the ongoing upgrade path. ### What happens when Maintenance ends? When Maintenance expires or is cancelled: - You keep every file installed up to that point. - Perpetual use rights are completely unaffected. - You no longer receive update notifications or access to newer versions. - Seller support access lapses. - You can renew Maintenance by hand at any time to restore update access. > **Warning:** Cancellation touches only the Maintenance subscription record -- it never > removes installed files or revokes the license. ### Is Maintenance required? No. Maintenance is optional. If you are satisfied with the installed version and do not need updates, security notices, or seller support, you can let Maintenance lapse or never purchase it. ### How far in advance do I get notified before a Maintenance renewal? About 7 days before the renewal date, everyone on the buyer workspace gets one email with the amount and the date. You get one reminder per renewal period. ### Can I pause Maintenance and resume later? You can cancel auto-renewal at any time. Access continues through the already-paid-for period. **Renew maintenance** stays on the license after a cancel, before and after the end date, so you can pay for another year whenever you like. If your term has not ended, the new year starts at the end of it; if it already ended, the new year starts on the day you pay. Renewing by hand does not turn auto-renew back on. Use **Turn auto-renew back on** for that. --- ## Pricing and Payments ### Are the first-party Recipes free? Yes. First-party Recipes are labeled "Free with any plan" in the **New project** dialog and carry no separate marketplace license fee. No payment method or coupon is needed. ### How do coupons work? Coupons are issued by Chipp. On the project's **Marketplace** tab, enter the code in the **Coupon / grant code** field next to the listing and click **Redeem**; the project receives a full license. There is no discount field in Stripe checkout. A coupon must cover the full price of the listing (for example a 100%-off grant); a coupon that covers only part of the price cannot be redeemed. Coupons may apply to one specific listing or to any listing, and may have expiry dates or redemption limits. ### Who am I paying? The seller. A marketplace purchase is charged on the seller's own Stripe account: the seller is the merchant of record, and your card statement and receipt show the seller. Chipp's marketplace fee is part of the price you see, not an extra charge. ### What is the refund policy? The seller is the merchant of record, so refunds are made on the seller's Stripe account. Ask the seller through their profile, or contact Chipp support and we will route the request. A listing does not carry any additional guarantee beyond what its detail page states. ### Does purchasing a Maintenance subscription auto-renew? Yes, by default. On the renewal date we charge the annual Maintenance price to the card you paid with at purchase. That card is saved on the seller's Stripe account, and the renewal is a charge by the seller, the same as the purchase. If the charge is declined, we try again 1 day and 3 days later; after the third failure Maintenance lapses and we email you. You can still renew by hand. You can cancel auto-renewal at any time from the project's **Marketplace** tab: expand the license under **Licenses on this project** and click **Cancel auto-renew**. Access continues through the paid period, and nothing is charged at renewal. --- ## Sellers ### How much does Chipp charge sellers? Chipp charges a platform fee on each transaction. The fee is currently set at **30%** of the gross purchase price. This applies to both one-time license purchases and annual Maintenance renewals. The fee is deducted at charge time as an application fee on the charge, so it never reaches your balance. At 30%: a $100 purchase leaves $70 for you. The fee is configurable and may be adjusted over time with advance notice to sellers; any adjustment applies only to transactions after the effective date. ### When do sellers get paid? At charge time, by Stripe. Pack, recipe, and bundle licenses and Maintenance renewals are charged on your own Stripe account (a Stripe Connect direct charge). You are the merchant of record, the charge lands in your Stripe balance minus Chipp's fee, and Stripe pays it out to your bank on your normal Stripe payout schedule. Chipp does not hold your money and runs no transfers to you. Whole-project sales are paid inside the buyer's payment to Chipp: Stripe sends your share to your connected Stripe account when the buyer pays. You need a connected Stripe account that can accept charges before you can publish a paid listing, and buyers cannot check out while it cannot accept charges. ### What happens on a refund or dispute? Your Stripe account carries it. A refund comes out of your Stripe balance, and Chipp returns its fee in proportion to the amount refunded, whether the refund was made by Chipp support or by you from your Stripe dashboard. A dispute follows Stripe's normal dispute process on your account. ### How do I become a seller? Click **Sell a Recipe** from the Marketplace browse view (or open **Sell Recipes** in the Alchemist sidebar). Under **Become a creator**, enter a display name and optional bio and click **Create seller profile**. Each tenant can have one seller profile. You can then draft listings from the same page. ### What goes through review before a listing is published? All listings -- new and updated -- go through automated static analysis, dependency auditing, and human review of manifest correctness, migration safety, and content policy. Review typically takes 1-3 business days for first submissions and 1 business day for updates to already-approved listings. ### Can I publish a free listing? Yes. Set the price to $0. Buyers cannot check out a $0 version through Stripe; they get it by redeeming a coupon or grant code. --- ## Technical ### What if an update breaks my customizations? Before any changes are written, **Preview update** shows the planned file changes and whether the update is a clean apply or needs AI reconciliation (your files have drifted from the pack's own content). If it needs reconciliation, **Apply (via AI reconciliation)** dispatches an Alchemist ticket that merges the update with your changes instead of overwriting them. Your current version stays live until that ticket lands. ### Do I have to accept every file in a reconciled update? There is no per-file accept or reject step. A reconciled update runs as an ordinary Alchemist ticket, so you review and steer it the same way as any other ticket, and you can roll back its commit through git history. ### Can I roll back a pack update? The platform does not provide a one-click rollback. However, since your project is a git repository, you can roll back through git history. The install analysis provenance record shows exactly which files were changed in each install, making it straightforward to revert specific files. ### What is the difference between a "clean apply" and "needs AI reconciliation" in the preview? - **Clean apply**: none of the files the update touches have drifted from the pack's own content. **Apply** commits the changes directly to the project's repo. - **Needs AI reconciliation**: at least one file has changed since the pack wrote it. **Apply (via AI reconciliation)** dispatches an AI ticket that merges the update with your changes instead of overwriting anything. ### How does the platform know which files I have modified? When a pack is installed, the platform records a cryptographic hash of each installed file as part of the provenance record. At analysis time, it compares the current file contents against the recorded hash to determine if you have modified the file since installation. --- ## Security and Trust ### How does Chipp verify packs before they are listed? Every listing goes through static analysis (vulnerability and secret scanning), dependency auditing against known CVE databases, and human review of manifest correctness, migration scripts, and agent-guidance notes. The Verified Publisher badge indicates Chipp has also confirmed the seller's identity. ### Is Marketplace review a security guarantee? No. Marketplace review reduces risk but does not guarantee that a pack is free of all vulnerabilities. Treat installed pack source with the same care as any third-party code: review the files, run your own tests, and report issues to the seller and to Chipp's security contact. ### What should I do if I find a security vulnerability in a published pack? 1. Contact the seller through the channel on their profile page. 2. Also report to Chipp via the security contact in the platform footer. 3. Practice coordinated disclosure -- do not publish the vulnerability publicly before the seller has had a reasonable opportunity to issue a patch. Chipp may temporarily delist or quarantine the affected version while the patch is in review. ### Does Chipp have access to my project's source code? The Alchemist platform operates on your project's codebase as part of normal development operations (reading files, writing changes, running tests). Chipp's data handling practices are covered in the [Privacy Policy](https://chipp.ai/privacy). ## Related guides - [Recipes, Feature Packs & the Marketplace](/docs/guides/alchemist-recipes-overview) -- the core vocabulary this FAQ assumes. - [Marketplace: Browse, Purchase & Create a Project](/docs/guides/alchemist-marketplace-browse-purchase) - [Marketplace: Install into an Existing Project](/docs/guides/alchemist-marketplace-install) - [Marketplace: Maintenance Subscriptions, Updates & Perpetual Rights](/docs/guides/alchemist-marketplace-maintenance) - [Marketplace Seller Guide: Publish Recipes & Feature Packs](/docs/guides/alchemist-marketplace-seller-guide) --- ============================================================ SECTION: Alchemist Operations ============================================================ # Alchemist: Deploys and Domains How deployments work on the Alchemist platform and how to attach custom domains. --- Every project has a **Live URL** on the platform's shared domain (for example `your-project.on.chipp.ai`). You can also attach one or more custom domains from the **Domains** tab. ## How deploys happen A deploy is triggered automatically whenever: - The agent's branch merges into your project's default branch. - You click **Redeploy** in the project's detail view. - You push a commit to the default branch yourself, directly to the platform-hosted repo -- no GitHub account, and no need to eject first. See [Clone Your App's Code and Develop Locally](/docs/guides/alchemist-local-development). - After ejecting your repo to your own GitHub org, your own CI pushes a commit and calls the platform's deploy API with a deploy token. Each deploy runs a build sandbox that produces a container image, then the platform's rollout controller pushes that image to the live pod behind the same URL. Crossover is a few seconds; in-flight requests finish on the old pod. > **Note:** **New projects hold releases for a human by default.** Projects are created > with the deploy gate in **Manual** mode: a project's very first deploy goes out > on its own, but after that, work the agent merges is built and then waits > until someone clicks **Deploy now**. Switch the gate to **Continuous** to ship > every merge as soon as it builds, or to **Scheduled** to release on a cadence. > See [Releases, the Deploy Gate, and Rollback](/docs/guides/alchemist-releases-and-rollback). ## Deploy pacing: rapid pushes coalesce Pushes are never rejected and never queue up into a backlog of rollouts. Every push is accepted immediately, and if another deploy for the same project is already waiting, the newer one **replaces** it: only the newest commit gets built. The older row stays visible in the deploys list marked *superseded*, with a pointer to the deploy that replaced it, so you can see what happened rather than watching a push disappear. Consecutive deploys for one project are spaced by a short window (about five minutes). Push three times in two minutes and you get one build of the newest commit, not three builds. Because the newest commit already contains the earlier ones, nothing is lost. A failed build does **not** consume that window, so a retry (or a fix you push straight after a failure) is picked up right away instead of waiting. ## Deployment configuration Everything about how your app runs is controlled by an optional `.alchemist/deployment.yaml` file in your repo. Omit the file, or any field in it, and you get the defaults. ```yaml # .alchemist/deployment.yaml resourceClass: medium # default: small replicas: 2 # default: 1 env: LOG_LEVEL: info FEATURE_X: enabled ``` | Field | Values | Notes | | --- | --- | --- | | `resourceClass` | `small` (default), `medium`, `large` | `xl` and `xxl` need approval first: email support@chipp.ai. | | `replicas` | 1 to 5 self-serve (default 1) | Above 5 total pods needs approval: email support@chipp.ai with your expected concurrency profile. Each pod is billed while it runs. | | `env` | up to 50 keys, 4KB each | Applied *after* the platform's own variables, so your value wins on a name collision. | The concurrency threshold counts **total pods**, so a `worker` block counts toward it: `replicas: 4` plus a worker is 8 pods and needs approval, while `replicas: 2` plus a single-replica worker is 3 and does not. ### What each resource class gets Each pod is guaranteed its *request* and can burst up to its *limit*: | Class | CPU request / limit | Memory request / limit | Access | | --- | --- | --- | --- | | `small` (default) | 0.25 / 0.5 vCPU | 256 MB / 512 MB | Self-serve | | `medium` | 0.5 / 1 vCPU | 512 MB / 1 GB | Self-serve | | `large` | 1 / 2 vCPU | 1 GB / 2 GB | Self-serve | | `xl` | 2 / 4 vCPU | 2 GB / 4 GB | Approval | | `xxl` | 4 / 8 vCPU | 4 GB / 8 GB | Approval | `replicas` is a fixed count, not an autoscaling range: the platform runs exactly the number of pods you declare, whatever the traffic. The one automatic adjustment is for memory: a pod that keeps running out of memory is moved up a class (`small` to `medium` to `large`, never into `xl` or `xxl`), and the project owner gets an email explaining why. ### Request time limit The load balancer in front of your app closes any single HTTP request after **10 minutes** (600 seconds), even if the response is still streaming. Anything that can run longer than that, such as processing a large document with AI or a bulk import, belongs in a [background worker](#background-workers): accept the request, record the job, return right away, and let the worker do the work and report progress. The schema is strict: an unknown field fails the build rather than being ignored, so a typo surfaces immediately instead of silently doing nothing. Anything that affects security posture (service account, secret references, network policy, namespace) is deliberately **not** settable from this file. Those are platform-controlled, so a bad or malicious push can never request elevated access for itself. ## Background workers By default one pod both serves your traffic and runs everything else your app does. If your app has real background work (scheduled jobs, a queue consumer, a long poll) you can move it into its own pod by declaring a `worker` block: ```yaml worker: replicas: 1 # default: same as `replicas` ``` Your traffic pod then receives `WORKER_ROLE=api` and the worker pod receives `WORKER_ROLE=worker`, both running the same image. > **Warning:** **Your app has to honor `WORKER_ROLE` before you declare this.** Both pods run > the same code, so if your background work is not gated on that variable it will > run in **both** pods: every scheduled job fires twice, every queue is consumed > twice. Gate the work on `WORKER_ROLE === "worker"`, and treat the variable being > absent as "run everything" so the app still behaves correctly when deployed > without a worker. > > Apps scaffolded from an Alchemist template now ship this gating already: a > `src/lib/worker-role.ts` helper plus every background starter wrapped in > `if (runsBackgroundWork)`. If your repo has that file, you can declare a worker > as-is. > > If your repo was forked from a template **before** that landed, it will not have > the file, and the gating did not reach you retroactively. Check for > `src/lib/worker-role.ts` first: if it is missing, port the gating before > declaring a worker, or your background work runs in both pods. Why bother: a deploy restarts the pod it rolls, so background work sharing the traffic pod gets interrupted on every deploy, and a long job competes with request latency. A separate worker pod also gets a much longer shutdown grace so in-flight work can finish, and it rolls without touching the pod serving your users. A worker is an additional running pod and is billed as one, on the same CPU and memory basis as your app pod. ## Force a redeploy If your Live URL stops responding or you want to ship a config change without a code change, open the project and click **Redeploy**. The platform resolves the current HEAD SHA of your default branch, enqueues a fresh deploy at that SHA, and returns the existing in-flight deploy if one is already running (so the button is safe to click twice). ## Auto-retry on transient failures Builds and rollouts sometimes fail for reasons that have nothing to do with your code -- registry rate-limits, transient auth blips, a flapping upstream mirror. The platform automatically retries a failed deploy up to **two times** (three attempts total) before surfacing the failure to you. While the auto-retry is in flight you'll see an amber banner: "Build failed, auto-retrying (attempt 2 of 3)", with a note that no action is needed. If all three attempts fail, a manual **Retry Deployment** button appears. At that point the failure is usually something the agent can fix -- open a ticket describing the error. ## Custom domains Every project can serve traffic on a domain you already own, in addition to (or instead of) buying one through the platform. Open the **Domains** tab to see both paths side by side: - **Find a domain** -- search for and buy a new domain through the platform. Domains are billed at the registrar's wholesale price plus a flat platform markup; the price you pay is shown at purchase and frozen on your invoice -- future markup changes never re-bill historical purchases. - **Connect existing domain or subdomain** -- bring a domain or subdomain you already own by adding two DNS records at your current DNS host. This is the path most teams want, and it's covered in detail below. The platform handles certificate issuance and renewal automatically for domains added through either path. ### Connecting a domain or subdomain you already own > **Note:** You do **not** change your domain's authoritative nameservers, and you never > delegate them to Chipp. Your domain keeps whatever nameservers (and DNS host) > it uses today -- you're just adding two records there. **1.** Pick a subdomain We recommend connecting a subdomain, such as `app.example.com`, rather than your apex/root domain (`example.com`). A subdomain keeps your main website on its existing setup and makes the DNS records below simpler to add without touching anything else on the domain. **2.** Open the Domains tab From your project, open the **Domains** tab and click **Connect existing domain or subdomain**. If you have more than one project, you'll be prompted to pick which project this domain should route to. **3.** Enter your hostname Type the hostname you chose, for example: ``` app.example.com ``` Do not include `https://` (or any path). **4.** Add the routing CNAME At your existing DNS host, add: | Type | Name / Host | Target / Value | |------|-------------|-----------------| | CNAME | your subdomain label (e.g. `app`) | `fallback.chipp.ai` | > **Warning:** **Using Cloudflare for DNS?** Set this record's proxy status to **DNS > only** (gray cloud), not proxied (orange cloud). A proxied record breaks > routing and certificate validation. **5.** Add the DCV/SSL validation CNAME Once you register the hostname in step 3, Alchemist generates a second, unique DCV (domain control validation) CNAME record for that hostname. Copy its **Name** and **Value** exactly as shown in the UI -- this record is unique per domain, so don't reuse one from another domain or guess at the value. > **Warning:** Same rule applies here: if you're on Cloudflare, this record must also be > **DNS only** (gray cloud), never proxied. **6.** Click Verify DNS Alchemist checks both records and, once they resolve correctly, issues the certificate automatically. There's no separate "activate HTTPS" step -- certificate issuance and renewal both happen automatically once verification succeeds. ### DNS records at a glance | Step | Type | Name / Host | Target / Value | |------|------|-------------|-----------------| | Routing | CNAME | your subdomain label (e.g. `app`) | `fallback.chipp.ai` | | DCV / SSL validation | CNAME | unique, shown in the Alchemist UI | unique, shown in the Alchemist UI | ### Propagation DNS changes typically propagate within minutes, but can take up to 48 hours depending on your provider and the record's TTL. If **Verify DNS** doesn't succeed right away, wait a bit and try again before troubleshooting further. ### Troubleshooting - **Verify DNS fails / CNAME not found** -- double-check the routing record's Name matches your subdomain label and the Value is exactly `fallback.chipp.ai` (no trailing dot mismatch, no typo). Confirm you added it at the DNS host your domain actually uses. - **Record present but still failing on Cloudflare** -- confirm both the routing and DCV records are set to **DNS only** (gray cloud). A proxied (orange cloud) record looks correct in the DNS panel but fails validation. - **It's been a while and it's still not verifying** -- propagation can take up to 48 hours depending on your provider and TTL; use a DNS lookup tool to confirm the records are visible from outside your network before assuming something is misconfigured. - **HTTPS still shows as pending** -- this is expected until both DNS records are verified and the DCV/SSL validation record has propagated. HTTPS activates automatically right after that; there's no manual step to trigger it. --- # Alchemist: Releases, the Deploy Gate, and Rollback How finished work goes live on Alchemist: the deploy gate's Continuous, Manual, and Scheduled modes, release-candidate QA, release notes, and one-step rollback. --- Merging work and putting it live are two separate steps. The agent merges finished work into your project's default branch; the **deploy gate** decides when that work reaches your live app. This page covers the gate, the checks you can put in front of a release, and how to undo one. ## The deploy gate Open your project's **Releases** tab and find the **Deploy gate** panel. It has three modes: | Mode | What happens to merged work | | --- | --- | | **Continuous** | Each merge is built and goes live as soon as the build finishes. | | **Manual** | Merges keep landing and are built, but nothing goes live until someone clicks **Deploy now**. | | **Scheduled** | Merged work is released on a cadence you set: every N hours, or at set times of day in your timezone. | New projects start in **Manual**. The project's first deploy still goes out on its own so the app comes up, but every release after that waits for a person. A daily release digest lists what is waiting. The panel shows what is pending, along with release notes generated from the changes since the last release, so whoever clicks **Deploy now** can see what they are shipping. ## Release-candidate QA When work is waiting to go live, the platform cuts a **release candidate**: a fixed snapshot of exactly what would ship. A QA agent can check that candidate and write a report (use **Start QA** or **Re-run QA** in the **Release-candidate QA** panel). The Deploy gate panel's **What the QA agent will check** list shows the steps drafted from the pending changes. Under **Quality gate** you choose how much weight the report carries: - **Advisory (default):** the report is there to read; it never blocks a release. - **Require a passing QA verdict to release:** a release needs the current candidate's QA to have passed. **Deploy now** can still override a failed or missing pass, and every override is recorded in the audit trail. - **Auto-release when QA passes:** in Manual or Scheduled mode, a passing QA releases the work on its own, optionally after a soak period of up to 24 hours (1,440 minutes). > **Note:** The quality gate checks the QA agent's verdict. It does not run your own test > suite: the platform build compiles and type-checks your code, but does not run > your tests. If your app has a test suite that must pass before a release, run it > on every change (for example in a ticket's acceptance check or your own CI) and > keep the gate in Manual mode so releases only go out after it passes. ## Rolling back The **Roll back** panel lists earlier completed deploys. Rolling back puts a previous deploy's already-built image back live. Nothing is rebuilt, so it takes about as long as any rollout. A rollback also **pins** the project. New work keeps merging, but none of it goes live until you click **Resume deploys**, so the next merge can't quietly re-ship the change you just rolled back. Resuming can also release anything that was held while the project was pinned. Rollbacks, pins, and resumes all appear in the panel's **Audit trail**. A rollback restores code, not data. Database changes and uploaded files are not reverted. See [Runtime, Data, and Regions](/docs/guides/alchemist-runtime-and-data) for how data is backed up. ## Related reading - [Deploys and Domains](/docs/guides/alchemist-deploys-and-domains) - [Runtime, Data, and Regions](/docs/guides/alchemist-runtime-and-data) --- # Alchemist: Embedded Chipp Agent Bind a Chipp AI agent to your Alchemist project and embed it in your application using inline panels, floating widgets, or backend calls. --- The **Embedded Chipp Agent** feature allows you to bind an existing Chipp AI agent to your Alchemist project and offer it to your end users through multiple interfaces: an **inline chat panel**, a **floating widget**, or **backend API calls** from your application server. This guide covers the complete workflow: installing the feature pack, binding an agent, and deploying one or more user interfaces. ## What is an embedded Chipp agent? A Chipp agent is a configured AI application with its own models, prompts, knowledge, and actions. When you bind an agent to an Alchemist project, you enable: - **Native UI**: inline panels and floating widgets styled to your project's design system (no iframe, no external domain) - **Backend integration**: your server can invoke the agent programmatically to power search, recommendations, or autonomous workflows - **Session management**: authenticated end-user sessions (with email) or anonymous visitor sessions (pseudonymous, no auth required) - **Consolidated billing**: usage is metered under the organization that owns the Chipp agent, appearing in the standard Chipp billing dashboard ## Core concepts ### Bindings A **binding** is the configuration that links a Chipp agent to an Alchemist project. It stores the **application ID** of the Chipp agent, whether anonymous visitors are allowed and how their chats are retained, and which page context keys the agent accepts. The identity mode (authenticated, anonymous, or both) and the installed surfaces are recorded when you generate the integration, and generating sets the binding's anonymous access to match the mode. You change retention, page context keys, and the chat session key in the project's **Settings** tab, under **Embedded agent settings**. A project has one active binding at a time. You can replace or remove it at any time; the generated session route resolves the active binding server-side. The binding itself is secure: secrets are never committed to your codebase. ### Identity modes When a user interacts with an embedded agent, they authenticate in one of two ways: 1. **Authenticated mode**: the user is signed in to your project. Your project's backend passes the signed-in user's ID and email when it mints the session, and Chipp keeps their conversation history across sessions. This is the default. 2. **Anonymous mode**: the user is not required to sign in. A pseudonymous visitor session is minted each time the chat mounts. Nothing is stored in a cookie, so a page reload starts a new visitor and a new conversation. This suits public websites where users should not be asked to sign up. You can also choose **both**: signed-in users get a signed-in session, everyone else an anonymous one. When an anonymous visitor signs in, the session is upgraded and the conversation moves to their account. This mode generates three session routes: `/session`, `/session/anonymous`, and `/session/upgrade`. For backend API calls, your server specifies the identity explicitly, with no implicit inference. ### Session endpoints The Alchemist project provides private backend endpoints (`/api/client/embed/session*`) for minting and managing user sessions. Your application's backend uses these endpoints to: - Create or upgrade user sessions - Rotate existing sessions - Revoke sessions on logout All endpoints require your project's **client key** with `scope: "full"`. (The Builder preview runs with a narrower key that can mint sessions but cannot upgrade, rotate, or revoke them.) These endpoints are never exposed to the browser; your frontend calls your own backend instead, which delegates to Chipp. ## Product rules To preserve data consistency and security: - **Same-org only**: You can only bind agents created in the same organization. Cross-org agents are never visible or bindable. - **No duplication**: Bindings reference existing agents; they never clone or provision new agents. Create agents through the normal Chipp app-creation flow, then bind them. - **Uninstall safety**: Removing the generated integration deletes the installed code and the binding (removing only the binding leaves the code in place), but **never deletes the underlying Chipp agent or user conversations**. Your agent data is preserved. - **Billing continuity**: Usage is billed normally through Chipp's metering, attributed to the organization that owns the bound agent's application. No new billing path. ## Next steps Choose your path based on how you want to surface the agent: - **[Install the feature pack](/docs/guides/alchemist-embedded-chipp-agent-install/)**: Register the feature and bind an agent to your project - **[Embed an inline panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/)**: Display the agent as a built-in part of your application interface - **[Embed a floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/)**: Display the agent as a persistent floating button that opens a chat window - **[Backend client integration](/docs/guides/alchemist-embedded-chipp-agent-backend/)**: Call the agent from your application server for search, recommendations, or workflows --- # Alchemist: Self-Healing The platform watches your deployed app's errors and behavior and files fix tickets automatically. --- Alchemist can watch your running app's logs and automatically open a fix-ticket when new problems show up -- so a regression doesn't sit unnoticed until a user reports it. You configure this on a project's settings page under **Self-healing**. There are two independent sweeps, each toggled and scheduled on its own: - **Error sweep** -- scans your app's **error** logs and, when new error signatures appear, opens a single batched fix-ticket describing them. Default cadence: every 30 minutes. - **Behavior sweep** -- reviews **warnings, errors, and breadcrumbs** across a window and opens a findings ticket for issues worth a closer look (not just hard crashes). Default cadence: weekly. ## Configuring cadence Each sweep has an **Every** dropdown. Leaving a sweep untouched runs it at the default cadence shown next to it. You can make a sweep more or less frequent, or turn it off entirely with its toggle. Sweep cadences are clamped to a range of every 30 minutes at most and every 30 days at least. ## Approval and cost cap **Before a fix runs** controls whether a sweep's fix starts on its own: - **Ask me first** (default): each fix waits for your approval in the project's **Approvals** tab. A fix with no decision expires after 48 hours. - **Run automatically**: the fix starts as soon as the sweep finds something. **Per-fix cap** sets the most one fix can spend (default $35). A fix that would cost more stops and asks for more budget. ## What you get When a sweep finds something new (and, in **Ask me first** mode, you approve it), it opens a normal ticket in your project -- so the fix flows through the same agent pipeline as any other work, and you can follow it in the Jobs view. Repeat occurrences of an error the platform has already filed are de-duplicated, so you won't get a fresh ticket every sweep for the same known issue. ## Notes - Sweeps only act on **new** signatures since the last run; a steady, already- ticketed error won't re-open tickets. - Turning a sweep off stops new tickets from that sweep immediately; it does not close tickets already opened. --- # Alchemist: Install & Bind the Embedded Agent Install the embedded-Chipp-agent feature pack and bind it to an existing agent in your organization. --- This guide walks you through installing the **embedded-Chipp-agent** feature pack in an existing Alchemist project and binding it to a Chipp agent in your organization. ## Prerequisites - A Chipp application (agent) in your organization, already created through the normal Chipp app-builder interface - An existing Alchemist SaaS project (created via the standard flow) - Project admin privileges in Alchemist ## Installation flow Installing the pack does these steps: 1. **List same-org agents**: shows the Chipp agents in your project's organization (cross-org agents are never listed) 2. **Select & bind**: you choose which agent to bind; the binding is created server-side 3. **Generate the integration**: the pack commits these files into your project: - `src/services/embedded-agent/router.ts`: the session proxy, mounted at `/api/embedded-agent`. Authenticated mode adds `/session`, anonymous mode adds `/session/anonymous`, and "Both" adds `/session`, `/session/anonymous`, and `/session/upgrade` 4. **Set anonymous access**: the binding's anonymous access is turned on for "Anonymous visitors only" and "Both", and off for "Authenticated users only". Without this, anonymous sessions are refused. - `src/services/embedded-agent/client.ts`: the server-side client that mints chat tokens - `src/services/embedded-agent/backend-example.ts`: a server-to-server example - `web/src/lib/embedded-agent/EmbeddedAgentPanel.svelte` (inline panel) and/or `EmbeddedAgentWidget.svelte` (floating widget) - A vendored browser client in `web/src/lib/embedded-agent/embed-client/`, a test, and agent guidance in `docs/agent-guidance/embedded-chipp-agent.md` ## Installation steps ### 1. Open the project's Settings tab In Alchemist, open the project and go to the **Settings** tab. ### 2. Bind an agent In the **Embedded agent** card, pick an agent from the dropdown (it lists the agents in your project's organization) and click **Bind agent**. The card then shows "Currently bound: [Agent Name]". ### 3. Generate the integration In the **Generate chat UI + backend integration** card below it: 1. Choose an **Identity mode**: "Authenticated users only", "Anonymous visitors only", or "Both". 2. Check the surfaces you want: **Inline panel**, **Floating widget**, or both. 3. Click **Generate integration**. When it finishes, the card shows "Integration active for [Agent Name]" with the identity mode, the installed surfaces, and the pack version. You can also ask Alchemist in chat to do this. It uses the `install_embedded_chipp_agent` tool. ### 4. Adjust the settings (optional) The **Embedded agent settings** card below has three controls: - **Anonymous visitors**: "Saved (like signed-in chats)" or "Not saved (kept up to 4 hours)". Shown only when anonymous access is on. - **Page context keys**: the context keys the agent accepts from your pages, comma separated, plus an optional max value length. Empty means no page context. If the project defines its agent in `chipp/agent.json`, every agent sync replaces this list with the file's `contextKeys`. - **Chat session key**: **Rotate key** replaces `CHIPP_PROJECT_CLIENT_KEY` and pushes the new key to your deployed app. The old key keeps working until you click **Revoke old key**, so revoke it after the app has restarted. ## Managing the binding ### Replace the binding In the **Embedded agent** card, pick a different agent and click **Replace binding**. The generated session route resolves the active binding server-side, so the session endpoint stays the same. ### Add a surface If you installed only one surface, the **Generate chat UI + backend integration** card shows **Add panel** or **Add widget**. Click it to add the missing surface. (In chat, Alchemist uses `add_embedded_chipp_agent_surfaces`.) ### Remove the integration In the **Generate chat UI + backend integration** card, click **Remove generated integration**. This: - Deletes the generated panel, widget, and session-route code from your project - Removes the binding - **Preserves** the Chipp agent and all user conversations The **Remove** button in the **Embedded agent** card removes only the binding and leaves the generated code in place. ## Environment & secrets The generated session proxy authenticates to the Alchemist API with a project client key (`alch_proj_...`) in the `CHIPP_PROJECT_CLIENT_KEY` environment variable. The platform provisions it when the pack is installed; you do not need to create it. If it is missing, the session route returns a 503 and the chat shows "Chat is not available right now." Two optional settings override the default hosts: - `CHIPP_PLATFORM_API_URL` (default `https://build.chipp.ai/alchemist-api`): where sessions are minted - `CHIPP_API_BASE_URL` (default `https://build.chipp.ai`): the Chipp chat runtime ## Troubleshooting ### "No agents found in this project's organization yet" - Create an agent in Chipp first, then come back to the **Settings** tab to bind it. - Only agents in the project's own organization are listed. An agent in a different organization cannot be bound. ### "Install was successful but I see no new files" - The pack commits its files to your project's repository. They live under `src/services/embedded-agent/` and `web/src/lib/embedded-agent/`. - Pull the latest changes or refresh your file tree. ### Chat shows "Chat is not available right now." - The session could not be minted. In authenticated mode the user must be signed in to your project. ("Both" mode falls back to an anonymous session for signed-out visitors.) - In anonymous or "Both" mode, check that the **Embedded agent settings** card does not say "Anonymous visitors are off". If it does, generate the integration again. - Verify the binding is still active in the **Settings** tab. ## Next steps Once the feature pack is installed and your agent is bound: - **[Inline chat panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/)**: Add the panel to specific pages - **[Floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/)**: Deploy a persistent chat widget - **[Backend client](/docs/guides/alchemist-embedded-chipp-agent-backend/)**: Integrate agent calls in your server routes --- # Alchemist: Embedded Agent: Inline Panel Embed a native chat panel as part of your application interface. --- The **inline panel** is a native chat interface that lives in your application alongside other content. Unlike the floating widget, it is part of your page layout and does not float over content. ## When to use the inline panel Use the inline panel when: - You want the agent on a **dedicated page or section** (for example a "Chat" or "Assistant" page) - The agent is a **core feature** of your application, not supplementary - You need **control over where the panel appears** (sidebar, main column, modal, and so on) For a launcher button that floats over your site, use the [floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/) instead. ## Basic setup ### 1. Install the feature pack Follow the [installation guide](/docs/guides/alchemist-embedded-chipp-agent-install/) first and check **Inline panel**. The pack adds the Svelte component `web/src/lib/embedded-agent/EmbeddedAgentPanel.svelte`. ### 2. Render the panel Import it in any page and place it where the chat should appear: ```svelte
``` On mount, the component calls your project's own session route (`POST /api/embedded-agent/session`; `/api/embedded-agent/session/anonymous` in anonymous mode; in "Both" mode the first, then the second if the visitor is signed out), gets a short-lived chat token, and renders the chat. The panel has a minimum height of `20rem` and fills the width of its container. ## Component props The component takes one optional prop: | Prop | Type | Purpose | |------|------|---------| | `context` | `Record` | Page context sent with each message, for example `{ page: "billing" }` | ```svelte ``` Rules for `context`: - Use only keys the binding allows (set in **Settings** > **Embedded agent settings** > **Page context keys**, or from `contextKeys` in `chipp/agent.json`, which replaces that list on every agent sync). The runtime drops other keys. - Never put personal data in it (names, emails, dates of birth, record IDs). Everything else (identity, token handling, styling) is handled for you. ## Authentication & identity The identity mode you chose at install time decides which session route the panel calls. You do not pass identity as a prop. - **Authenticated**: the session route requires a signed-in user in your project and mints the session with that user's ID and email. The user's conversations are kept across sessions, and the panel loads previous messages on mount. The panel re-mints the session every 10 minutes so the agent keeps access to your app's tools in a long conversation. - **Anonymous**: the session route mints a pseudonymous visitor session. Nothing is stored in a cookie, so a page reload starts a new visitor and a new conversation. - **Both**: a signed-in user gets an authenticated session; a signed-out visitor gets an anonymous one. When the visitor signs in, the panel upgrades the session and keeps the conversation. After an SPA login (no page reload), call `notifyEmbeddedAgentSignedIn()` from `web/src/lib/embedded-agent/session-client.ts`. See [Session upgrading](/docs/guides/alchemist-embedded-chipp-agent-identity-and-billing/#session-upgrading-anonymous-to-authenticated). If the session cannot be minted (the user is signed out, or the feature is not configured), the panel shows "Chat is not available right now." instead of failing the page. ## Styling & customization The panel renders natively (no iframe), so it inherits your page's fonts. Colors and shapes come from `--chipp-embed-*` CSS variables, which fall back to your design tokens (`--primary`, `--background`, `--foreground`, `--border`, `--radius`): | Variable | Default | |----------|---------| | `--chipp-embed-accent-color` | `var(--primary, #4f46e5)` | | `--chipp-embed-background` | `var(--background, #ffffff)` | | `--chipp-embed-foreground` | `var(--foreground, #111111)` | | `--chipp-embed-muted` | `var(--muted-foreground, #6b7280)` | | `--chipp-embed-border-color` | `var(--border, #e5e7eb)` | | `--chipp-embed-radius` | `var(--radius, 0.5rem)` | | `--chipp-embed-error-color` | `#dc2626` | | `--chipp-embed-font-family` | `inherit` | Set any of them on a wrapper element: ```css .chat-wrapper { --chipp-embed-accent-color: #0f766e; --chipp-embed-radius: 0.75rem; } ``` ## Errors and retries If a message fails to send (network, CORS, a 4xx or 5xx, a stream error), the panel marks it "not sent" with an inline error and a **Retry** button. If history fails to load, the panel shows a banner with **Retry**. ## Troubleshooting ### Panel shows "Chat is not available right now." - In authenticated mode, confirm the user is signed in to your project. - Confirm the binding is active in the project's **Settings** tab. - Check your server logs for `Embedded agent session` entries. A missing `CHIPP_PROJECT_CLIENT_KEY` returns 503; a failed mint returns 502. ### Messages not persisting across sessions - In anonymous mode this is expected: each page load is a new visitor. - In authenticated mode, conversations are tied to the signed-in user. ### Styling does not match my design system - Set the `--chipp-embed-*` variables (see "Styling & customization" above), or define the design tokens they fall back to. ## Next steps - **[Floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/)**: add a floating chat widget - **[Backend client](/docs/guides/alchemist-embedded-chipp-agent-backend/)**: call the agent from your server routes --- # Alchemist: Embedded Agent: Floating Widget Add a persistent, floating chat widget that users can toggle on any page. --- The **floating widget** is a toggleable chat interface that floats over your application content. It appears as a launcher button in the bottom-right corner and opens a chat panel when clicked. ## When to use the floating widget Use the floating widget when: - The agent is **supplementary** to your main application (support, help, search assistant) - You want a **low-intrusion** interface that users can open, minimize, and close - You want the agent available on **every page** with one line of code For an agent interface that is part of your page layout, use the [inline panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/) instead. ## Basic setup ### 1. Install the feature pack Follow the [installation guide](/docs/guides/alchemist-embedded-chipp-agent-install/) first and check **Floating widget**. The pack adds the Svelte component `web/src/lib/embedded-agent/EmbeddedAgentWidget.svelte`. ### 2. Render the widget Place it once, for example in `App.svelte`: ```svelte ``` On mount, the component calls your project's own session route (`POST /api/embedded-agent/session`; `/api/embedded-agent/session/anonymous` in anonymous mode; in "Both" mode the first, then the second if the visitor is signed out), gets a short-lived chat token, and renders the launcher. ## Component props The component takes one optional prop: | Prop | Type | Purpose | |------|------|---------| | `context` | `Record` | Page context sent with each message, for example `{ page }` | ```svelte ``` Rules for `context`: - Use only keys the binding allows (set in **Settings** > **Embedded agent settings** > **Page context keys**, or from `contextKeys` in `chipp/agent.json`, which replaces that list on every agent sync). The runtime drops other keys. - Never put personal data in it (names, emails, dates of birth, record IDs). The generated component docks to the bottom-right corner. The vendored client in `web/src/lib/embedded-agent/embed-client/` also supports `position: "bottom-left"`, `initiallyOpen`, `launcherLabel`, `panelLabel`, and `onStateChange`; edit the `mountChippEmbedWidget(...)` call in the component to use them. ## Widget behavior - The launcher opens the chat. The open panel has **Minimize chat** and **Close chat** buttons. - The launcher shows an unread badge when the agent replies while the panel is closed or minimized. - On screens 480px wide or narrower, the open panel fills the whole screen and respects the device safe areas. - If the session cannot be minted (the user is signed out, or the feature is not configured), the widget shows "Chat is not available right now." instead of failing the page. ## Authentication & identity The identity mode you chose at install time decides which session route the widget calls. You do not pass identity as a prop. - **Authenticated**: the session route requires a signed-in user in your project and mints the session with that user's ID and email. The widget re-mints the session every 10 minutes so the agent keeps access to your app's tools in a long conversation. - **Anonymous**: the session route mints a pseudonymous visitor session. Nothing is stored in a cookie, so a page reload starts a new visitor and a new conversation. - **Both**: a signed-in user gets an authenticated session; a signed-out visitor gets an anonymous one. When the visitor signs in, the widget upgrades the session and keeps the conversation. After an SPA login (no page reload), call `notifyEmbeddedAgentSignedIn()` from `web/src/lib/embedded-agent/session-client.ts`. See [Session upgrading](/docs/guides/alchemist-embedded-chipp-agent-identity-and-billing/#session-upgrading-anonymous-to-authenticated). ## Styling & customization The widget uses the same `--chipp-embed-*` variables as the [inline panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/#styling--customization), plus these for the floating chrome: | Variable | Default | |----------|---------| | `--chipp-embed-widget-size` | `3.5rem` (launcher size) | | `--chipp-embed-widget-offset` | `1.5rem` (distance from the viewport edge) | | `--chipp-embed-widget-z-index` | `2147483000` | | `--chipp-embed-widget-panel-width` | `380px` | | `--chipp-embed-widget-panel-height` | `600px` | ```css :root { --chipp-embed-widget-offset: 2rem; --chipp-embed-widget-z-index: 50; } ``` ## Troubleshooting ### Widget button not visible - Verify the component is rendered (not inside a conditional that is false). - If another element covers it, check `--chipp-embed-widget-z-index`. - If the widget shows "Chat is not available right now.", the session could not be minted (see below). ### Widget shows "Chat is not available right now." - In authenticated mode, confirm the user is signed in to your project. - Confirm the binding is active in the project's **Settings** tab. - Check your server logs for `Embedded agent session` entries. A missing `CHIPP_PROJECT_CLIENT_KEY` returns 503; a failed mint returns 502. ### Chat resets - Chat tokens last 1 hour. In authenticated mode the widget re-mints every 10 minutes. - In anonymous mode each page load is a new visitor, so a reload starts a new conversation. ## Next steps - **[Inline panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/)**: embed a panel as part of your layout - **[Backend client](/docs/guides/alchemist-embedded-chipp-agent-backend/)**: call the agent from your server routes --- # Alchemist: Embedded Agent - Backend Client Call a bound Chipp agent from your application server for search, recommendations, or autonomous workflows. --- The **backend client** lets your application server invoke a bound Chipp agent programmatically. Use it to power search features, generate recommendations, automate workflows, or any server-side task that benefits from an AI agent. Unlike the frontend UI (inline panel or widget), the backend client is never exposed to the browser. Your server controls the request, manages timeouts and retries, and processes the response. ## What the pack generates There is no separate package to install. When the embedded-Chipp-agent feature pack is installed, it writes these files into your project: | File | What it does | |------|--------------| | `src/services/embedded-agent/client.ts` | `mintEmbedSession()`: mints a short-lived chat token on the server. The only code that reads `CHIPP_PROJECT_CLIENT_KEY`. | | `src/services/embedded-agent/backend-example.ts` | `askEmbeddedAgent()`: a working example of a server-to-server call. Adapt or delete it. | | `web/src/lib/embedded-agent/embed-client/transport.ts` | `createHttpEmbedTransport()`: the chat transport (threads, messages, streaming). The browser panel and widget use the same one. | ### Environment variables | Variable | Default | Purpose | |----------|---------|---------| | `CHIPP_PROJECT_CLIENT_KEY` | (none) | Your project's `alch_proj_...` key. The platform provisions it when the pack is installed. Never expose it to the browser. | | `CHIPP_PLATFORM_API_URL` | `https://build.chipp.ai/alchemist-api` | Where chat tokens are minted. | | `CHIPP_API_BASE_URL` | `https://build.chipp.ai` | The Chipp chat runtime the token is used against. | ## Quick start ### Non-streaming (wait for the complete answer) The generated example does this for you: ```typescript import { askEmbeddedAgent } from '@/services/embedded-agent/backend-example.ts'; const answer = await askEmbeddedAgent( 'user_123', // externalUserId: your stable user id 'user@example.com', // email 'What are the trending products this week?', ); console.log(answer); // Agent's full reply as a string ``` ### Streaming (receive response text in real time) Mint a session, create a thread, and iterate the stream: ```typescript import { mintEmbedSession } from '@/services/embedded-agent/client.ts'; import { createHttpEmbedTransport } from '../../../web/src/lib/embedded-agent/embed-client/transport.ts'; const minted = await mintEmbedSession({ mode: 'authenticated', externalUserId: 'user_123', email: 'user@example.com', }); if (!minted.ok) throw new Error(`embedded agent unavailable: ${minted.code}`); const transport = createHttpEmbedTransport({ baseUrl: minted.session.runtimeBaseUrl, token: minted.session.token, applicationId: minted.session.applicationId, }); const thread = await transport.createThread(); for await (const event of transport.sendMessage(thread.id, 'Summarize my last 10 orders', { clientMessageId: crypto.randomUUID(), })) { if (event.type === 'text-delta') { process.stdout.write(event.delta); } else if (event.type === 'citations') { console.log('Citations:', event.citations); } else if (event.type === 'error') { throw new Error(event.message); } } ``` ## Minting a session `mintEmbedSession(identity)` never throws. It returns a typed result: ```typescript type MintResult = | { ok: true; session: { token: string; applicationId: string; expiresAt: string; runtimeBaseUrl: string } } | { ok: false; status: 502 | 503; code: 'not_configured' | 'session_mint_failed' }; ``` - `not_configured` (503): `CHIPP_PROJECT_CLIENT_KEY` is not set. - `session_mint_failed` (502): the mint request failed or returned an unexpected body. Session tokens last **1 hour**. Mint a new one when it expires. ## Transport methods `createHttpEmbedTransport({ baseUrl, token, applicationId })` returns: | Method | Purpose | |--------|---------| | `createThread()` | Start a new conversation. Returns `{ id, title, updatedAt }`. | | `listThreads()` | List this user's own threads. | | `getHistory(threadId)` | Load the stored messages of a thread. | | `sendMessage(threadId, text, { clientMessageId, signal?, hostContext? })` | Send a message and stream the reply. | | `cancel(threadId)` | Stop an in-flight reply. Safe to call when nothing is running. | `hostContext` is optional page or record context for one message (string, number, or boolean values). The runtime drops any key that is not listed in `contextKeys` in `chipp/agent.json`. Never put personal data in it. ## Streaming events ```typescript type EmbedStreamEvent = | { type: 'start'; messageId: string; threadId: string } | { type: 'text-delta'; delta: string } | { type: 'citations'; citations: { id: string; title: string; fileType: string }[] } | { type: 'done'; finishReason: string } | { type: 'ping' } | { type: 'conversation-frozen'; tagId: string } | { type: 'error'; message: string; code?: string } | { type: 'tool-confirmation'; confirmationId: string; toolName: string; title: string; summary: string; expiresAt: string } | { type: 'tool-confirmation-resolved'; confirmationId: string; decision: 'approved' | 'declined' | 'expired' }; ``` There are no separate tool-call or file events on this stream. A `tool-confirmation` event means the agent wants to change data in your app; nothing runs until a person confirms it. ## Identity management Identity is always explicit. You pass it to `mintEmbedSession()`. ### Authenticated users ```typescript const minted = await mintEmbedSession({ mode: 'authenticated', externalUserId: user.id, // Stable, unique per user email: user.email, name: user.name, // Optional }); ``` **Important:** `externalUserId` should be stable and unique per user. Conversations are attributed to this identity; changing it gives the user a separate history. ### Anonymous/visitor sessions ```typescript const minted = await mintEmbedSession({ mode: 'anonymous' }); ``` Anonymous sessions work only when anonymous access is enabled on the project's binding. Generating the integration in `anonymous` or `both` mode turns it on. Each anonymous mint creates a new visitor, so reuse the token for the visitor's conversation instead of minting per message. ### Upgrading an anonymous session ```typescript const upgraded = await upgradeEmbedSession( { externalUserId: user.id, email: user.email, name: user.name }, anonymousToken, // the visitor's current anonymous token, or undefined ); if (upgraded.ok) { // upgraded.session: { token, applicationId, expiresAt, runtimeBaseUrl } // upgraded.merged: true when the anonymous conversation moved to the user } ``` `upgradeEmbedSession` is in `src/services/embedded-agent/client.ts` (pack 2.4.0 and later). It never throws: a missing key is `{ ok: false, status: 503 }` and any upstream failure `{ ok: false, status: 502 }`. Take the identity from your server session, never from a request body. In "Both" mode the generated router already exposes this as `POST /api/embedded-agent/session/upgrade`. ## Errors - A failed transport call throws `EmbedTransportError` with `status` (HTTP status) and `detail` (the raw response body, usually `{ "error": { "code", "message" } }`). - A network failure surfaces as a `TypeError` from `fetch`. - A problem during a reply arrives as an `error` event on the stream. ### Error codes | Code | Where | Meaning | |------|-------|---------| | `rate_limited` | HTTP 429 | More than 30 requests per minute for this user | | `thread_not_found` | HTTP 404 | The thread does not exist or belongs to another user | | `billing_blocked` | `error` stream event | The organization that owns the agent is out of credits or blocked by a billing gate | An expired or revoked token is rejected with HTTP 401 (`invalid_token`). Mint a new session and retry. ## Cancellation Pass an `AbortSignal` to stop a request: ```typescript const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 30_000); try { for await (const event of transport.sendMessage(thread.id, 'Generate a report', { clientMessageId: crypto.randomUUID(), signal: controller.signal, })) { // ... } } finally { clearTimeout(timeoutId); } ``` To stop a reply on the server too, call `transport.cancel(thread.id)`. ## Idempotency Every send takes a `clientMessageId`. If you retry the same send, reuse the same value: the runtime collapses a duplicate it receives within 10 seconds into the original turn instead of creating a second one. ```typescript const clientMessageId = 'order-abc123-1692360000'; // Reuse on retry ``` This is a short dedupe window for retries, not a permanent guarantee. For operations that must never run twice (for example, placing an order), enforce idempotency in your own tool or data layer. ## Common use cases ### Search feature ```typescript app.post('/search', async (c) => { const { query } = await c.req.json(); const user = getUser(c); const answer = await askEmbeddedAgent(user.id, user.email, `Search for: ${query}`); return c.json({ results: answer }); }); ``` ### Recommendation engine ```typescript async function generateRecommendations(user: { id: string; email: string }, context: unknown) { const prompt = `Based on this context, generate 5 recommendations: ${JSON.stringify(context)}`; return await askEmbeddedAgent(user.id, user.email, prompt); } ``` ### Conversation resumption Keep the thread id and the session, then send to the same thread: ```typescript for await (const event of transport.sendMessage(threadId, 'What else can I help with?', { clientMessageId: crypto.randomUUID(), })) { // ... } ``` A thread belongs to the identity that created it, so resume it with a session minted for the same user. ## Billing & attribution Requests via the backend client are billed through the normal Chipp metering path, attributed to the organization that owns the bound agent's application. Your organization receives the invoice; no separate billing occurs. For cost control, consider: - Setting reasonable timeouts to avoid long-running requests - Monitoring token usage via the Chipp dashboard - Implementing rate limiting on backend endpoints that call the agent ## Troubleshooting ### `not_configured` - `CHIPP_PROJECT_CLIENT_KEY` is not set in the project's environment. The platform provisions it when the pack is installed. ### `session_mint_failed` - Verify the key is an `alch_proj_...` key for this project with full scope. - Verify the project has an active agent binding. - Check `CHIPP_PLATFORM_API_URL` if you overrode it. ### HTTP 401 from the chat runtime - The session token expired (1 hour) or was revoked. Mint a new session. ### `rate_limited` - Slow down requests for this user, or spread work across time. ### Long replies - Process events as they arrive instead of waiting for the full stream. - Consider breaking large requests into multiple smaller requests. ## Next steps - **[Inline panel](/docs/guides/alchemist-embedded-chipp-agent-inline-panel/)** - Embed UI for end users - **[Floating widget](/docs/guides/alchemist-embedded-chipp-agent-widget/)** - Persistent chat widget - **[Installation guide](/docs/guides/alchemist-embedded-chipp-agent-install/)** - Bind an agent to your project --- # Alchemist: Embedded Agent - Identity & Billing Understand authenticated vs. anonymous sessions and how billing is attributed. --- The embedded-Chipp-agent supports two identity modes for end users: **authenticated** (your app's own signed-in users) and **anonymous** (pseudonymous, no login required). This guide covers when to use each, how they work, and billing attribution. ## Identity modes ### Authenticated mode Authenticated users are the people who are **signed in to your app**. Chipp does not show its own login. Your project's session route (`POST /api/embedded-agent/session`, generated by the pack) requires your app's login, reads the current user, and mints a chat session for that user's id, email, and name. **When to use:** - SaaS applications with registered user accounts - When you want to attribute conversations to a specific person - When users have account-specific context (order history, preferences, etc.) **Flow:** 1. User signs in to your app as usual 2. User opens the chat panel or widget 3. The component calls your session route, which mints a short-lived chat token on the server 4. Conversations are attributed to that user's email **Session TTL:** chat tokens last 1 hour. The generated panel and widget mint a fresh token every 10 minutes while open, so a long chat keeps working. If the user signs out of your app, your session route stops minting tokens. **Conversation history:** Conversations are stored under the user's email. If the same user opens the chat from a different device, they see their conversation history. ### Anonymous mode Anonymous users are **not required to log in**. Instead, a pseudonymous **visitor session** is created for them. **When to use:** - Public websites or landing pages - When you want low friction (no login required) - Floating widgets for general visitors - Evaluation / freemium experiences **Flow:** 1. User opens the chat panel or widget (no login prompt) 2. The component calls `POST /api/embedded-agent/session/anonymous`, which mints a token for a new pseudonymous visitor 3. Conversations begin immediately **Session TTL:** 1 hour. The generated components mint a new anonymous session each time they load, so a page reload starts a new visitor and a new conversation. **Conversation history:** By default, anonymous conversations are stored like any other conversation. A binding can instead be set to `ephemeral` retention, which keeps anonymous conversations in a short-lived store (up to 4 hours) and never writes them to the database. Choose this in the project's **Settings** tab, under **Embedded agent settings** > **Anonymous visitors**. Anonymous access must be on for the binding; generating the integration in `anonymous` or `both` mode turns it on, and a binding without it rejects anonymous sessions. ## Choosing a mode | Scenario | Recommended | Why | |----------|-------------|-----| | SaaS app with user accounts | **Authenticated** | Link conversations to user identity; retain history | | Public website / marketing site | **Anonymous** | Low friction; no login required | | Floating support widget | **Either** | Authenticated if you want to track user history; anonymous for open access | | Free trial / freemium | **Anonymous, then Authenticated** | Start anonymous, upgrade when user signs up | | Internal tool / employee app | **Authenticated** | Link to employee identity for compliance and support | ## Session upgrading (anonymous to authenticated) A common pattern is to start users as anonymous (low friction) and upgrade them to authenticated when they sign up or log in. Choose the **Both** identity mode for this. The pack then generates the whole flow. ### What "Both" mode generates - **Session start:** the panel and widget try `POST /api/embedded-agent/session` first. If the visitor is not signed in (`401`), they start an anonymous session with `POST /api/embedded-agent/session/anonymous`. - **Upgrade route:** `POST /api/embedded-agent/session/upgrade` in `src/services/embedded-agent/router.ts`. It requires your app's login. The browser sends only `{ "anonymousToken" }`. The route takes the user's id, email, and name from your server session (never from the request body) and calls the platform's upgrade endpoint through `upgradeEmbedSession()` in `src/services/embedded-agent/client.ts`. It returns `{ token, applicationId, expiresAt, runtimeBaseUrl, merged }`. - **Browser helpers** in `web/src/lib/embedded-agent/session-client.ts`: `upgradeEmbeddedAgentSession(anonymousToken)` and `notifyEmbeddedAgentSignedIn()`. ### What you do when a visitor signs in - **Sign-in with a page reload** (a redirect or a form post): nothing. The components keep the anonymous token for the browser tab (`sessionStorage`) and upgrade it on the next load. - **Sign-in without a reload** (an SPA login): call `notifyEmbeddedAgentSignedIn()` right after login succeeds. Any anonymous panel or widget on the page upgrades and keeps the conversation. After the upgrade, the components mint a normal signed-in session too, so the agent gets your app's agent tools. The upgrade endpoint requires a full-scope project client key. The Builder preview's narrower key cannot upgrade, so in the preview the anonymous conversation does not carry over; the deployed app carries it over. If your integration was generated in "Authenticated users only" or "Anonymous visitors only" mode, it has no upgrade route. Generate it again in "Both" mode to get one. ### What happens after upgrade - The user's **anonymous conversation** is merged into their authenticated identity (`merged: true`) - The anonymous token is revoked - Future messages are attributed to the authenticated email - If the user opens the chat from another device, they see the full conversation history - A missing or expired `anonymousToken` is not an error: the user still gets an authenticated session, with nothing to merge (`merged: false`) ## Session endpoints (backend) Your application's backend calls these endpoints on `CHIPP_PLATFORM_API_URL` (default `https://build.chipp.ai/alchemist-api`). They are never exposed to the browser. Every response wraps its fields in `data`. ### Create authenticated session ``` POST /api/client/embed/session Content-Type: application/json Authorization: Bearer {projectClientKey} { "externalUserId": "user_123", "email": "user@example.com", "name": "Ada" } ``` `externalUserId` and `email` are required; `name`, `workspaceId`, and `sessionScope` are optional. Returns: ```json { "data": { "token": "...", "expires_at": "2026-08-20T10:30:00Z", "application_id": "..." } } ``` ### Create anonymous session ``` POST /api/client/embed/session/anonymous Content-Type: application/json Authorization: Bearer {projectClientKey} {} ``` Returns the same fields plus `retention` (`"retained"` or `"ephemeral"`). ### Upgrade anonymous to authenticated ``` POST /api/client/embed/session/upgrade Content-Type: application/json Authorization: Bearer {projectClientKey} { "anonymousToken": "...", "externalUserId": "user_123", "email": "user@example.com" } ``` Returns the same fields plus `merged` (boolean). ### Rotate session (refresh token) ``` POST /api/client/embed/session/rotate Content-Type: application/json Authorization: Bearer {projectClientKey} { "token": "..." } ``` Returns a new token with a fresh TTL. An invalid, expired, or revoked token returns HTTP 400 with code `invalid_session`. ### Revoke session ``` POST /api/client/embed/session/revoke Content-Type: application/json Authorization: Bearer {projectClientKey} { "token": "..." } ``` Immediately invalidates the token and returns `{ "data": { "revoked": true } }`. Revoking an already invalid token is not an error. Upgrade, rotate, and revoke require a full-scope project client key. ## Billing attribution Usage is billed through the **normal Chipp metering path**. Every message sent to the bound agent is metered and attributed to the organization that owns the agent's application. ### How it works 1. Your Alchemist project binds a Chipp agent (e.g., `app_abc123`) 2. End users interact with that agent (via UI, backend client, or API) 3. Chipp records each interaction (message, token count, etc.) 4. The **application owner's organization** (`org_xyz`) receives the invoice 5. You see usage in **Settings > Billing** for that organization ### Example - **Organization:** `org_acme` (your company, Acme Inc.) - **Agent:** `app_support` (customer support bot) - **Bound to:** Alchemist project `proj_website` - **Users:** 1,000 customers using the floating widget on `www.acme.com` - **Billing:** `org_acme` is billed for all 1,000 customer interactions (token usage, etc.) ### Cost estimation Costs depend on: - **Number of messages:** Each user message = 1 metered interaction - **Token usage:** Agent responses consume tokens based on model (GPT-4, Claude, etc.) - **Custom actions:** Tool calls and integrations may incur additional costs - **Rate:** Chipp's standard metering rates apply (see [Pricing](/pricing)) To estimate costs, multiply: ``` (messages per user) x (avg tokens per response) x (rate per 1K tokens) x (# users) ``` ### Cost control strategies 1. **Set reasonable timeouts** - Prevent long-running requests that consume unnecessary tokens 2. **Monitor usage** - Check the Chipp dashboard weekly to track token consumption 3. **Limit capabilities** - Disable expensive features (file uploads, long knowledge bases) if unneeded 4. **Rate limiting** - Implement application-level rate limits on chat endpoints 5. **Anonymous mode** - For public websites, use anonymous mode to keep exploration costs low ## Privacy & data retention ### Authenticated sessions - User email and conversations are stored in Chipp - Conversations are attributed to the email address - User can request data export or deletion (contact support) ### Anonymous sessions - **No personally identifiable information** is collected - Session ID is pseudonymous (not linked to user identity) - With the default `retained` setting, conversations are stored like any other; with `ephemeral`, they are kept only in a short-lived store - Inactive anonymous visitors are removed after 90 days - If upgraded to authenticated, the conversation is merged into the user's identity ## Multi-tenant applications For multi-tenant SaaS (multiple customers sharing one Alchemist project), ensure proper data isolation: 1. **Use a distinct identity per user.** Conversations are scoped to the user's identity (keyed by email), so one user never sees another user's threads. 2. **Pass tenant context per message** with `hostContext`, using only keys you list in `contextKeys` in `chipp/agent.json`: ```typescript transport.sendMessage(threadId, 'Help me', { clientMessageId: crypto.randomUUID(), hostContext: { tenantPlan: 'enterprise' }, }); ``` The runtime drops any key not on that list. Never put personal data in it. 3. **Scope prompts to tenant** - Write the bound agent's system prompt to respect tenant context Usage is billed to the agent owner's organization as a whole; there is no per-tenant billing breakdown. ## GDPR / data deletion If a user requests data deletion: 1. **Revoke their session** - Invalidates the active token ``` POST /api/client/embed/session/revoke { "token": "..." } ``` 2. **Contact Chipp support** - Request deletion of the user's conversation threads - Specify the email address and date range 3. **Delete local cache** - Remove any session tokens your app stored client-side ## Troubleshooting ### "User sees different conversation history on different devices" - In **authenticated mode**, all devices see the same history (email-based). Verify the email is consistent. - In **anonymous mode**, each page load starts a new visitor. This is expected behavior. - To fix, use authenticated mode. ### "Session expired" - Tokens last 1 hour in both modes. The generated components re-mint authenticated tokens every 10 minutes. If you mint tokens yourself, rotate before expiry: `POST /api/client/embed/session/rotate` - **Anonymous:** prompt users to sign in for persistent history. ### "User upgraded from anonymous, but old conversation was lost" - With the generated integration, check the identity mode is "Both", and that an SPA login calls `notifyEmbeddedAgentSignedIn()` - In the Builder preview the conversation never carries over (the preview key cannot upgrade); test on the deployed app - Verify the upgrade request sent the visitor's **current** anonymous token - Check `merged` in the upgrade response: `false` means no valid anonymous token was presented - Each anonymous session is a separate visitor; upgrading one does not affect others ### "Different organizations seeing each other's conversations" - This should not happen (conversations are scoped by user and agent) - Contact Chipp support if you suspect a data leak ## Next steps - **[Installation guide](/docs/guides/alchemist-embedded-chipp-agent-install/)** - Bind an agent - **[Pricing](/pricing)** - Understand Chipp pricing --- ============================================================ SECTION: Alchemist API & Automation ============================================================ # Alchemist: API Keys Mint and manage tenant API keys for programmatic access to the Alchemist platform. --- API keys authenticate programmatic access to the platform -- the [MCP server](/docs/guides/alchemist-mcp-server), CI scripts, or any direct HTTP call. A key is scoped to your tenant: it can act on your projects and tickets, and nothing else. ## Create a key Open the **Alchemist** tab and pick **API Keys** in the sidebar (under **Platform**; on a new project it sits behind **More**). You can also get there from a project's **Settings** tab with the **Create or view tenant Alchemist API key** button. Type a name (e.g. `claude-code`, `ci`) and click **Create key**. The full secret -- `alch_` followed by 64 hex characters -- is shown **once**, with a **Copy key** button and a ready-to-paste Claude Code command. Copy it immediately; it is never displayed again. Treat it like a password. Who can create keys: - Only a tenant **owner** or **admin**, signed in to the dashboard. Members get a "only a tenant owner or admin" message. - A key cannot create or revoke other keys. A leaked key therefore cannot mint its own replacement before you revoke it. - A tenant can hold up to 50 active keys. Revoke unused ones to make room. `alch_` keys are not the `chipp_sk_` keys on **Settings > MCP Access**. The Alchemist API and MCP server accept only `alch_` keys. ## Use a key Pass it as a bearer token on any `/api/*` request: ``` curl https://build.chipp.ai/alchemist-api/api/jobs \ -H "Authorization: Bearer alch_your_key_here" ``` The same key authenticates the MCP server at `https://build.chipp.ai/alchemist-api/api/mcp` for clients that send a bearer header (Claude Code, Claude Desktop, Cursor). Hosted connectors that only take a URL (claude.ai, ChatGPT) connect via OAuth instead and need no key -- see the [MCP server](/docs/guides/alchemist-mcp-server) doc. ## Revoke a key On the same **API Keys** page, click **Revoke** on any key and confirm. Revocation takes effect immediately -- the next request with that key is rejected. Revoking is a soft delete, so the key stays in the list (marked **Revoked**) and audit history never breaks. Create a replacement key before revoking one that something depends on. Only owners and admins can revoke. ## Good hygiene - One key per consumer (per machine / per CI pipeline), so you can revoke a single leaked key without disrupting the others. - Keys are write-only at the API: no endpoint ever returns a key's secret after creation, and the dashboard only ever shows the prefix. - Check **Last used** on the API Keys page. A key that says **Never** after a few weeks is a good candidate to revoke. --- # Alchemist Cloud Tickets MCP Drive your Alchemist Cloud tickets from any MCP client: dispatch, list, read status, reply to a paused question, read logs, query your app's database. --- The **Alchemist Cloud Tickets MCP** server lets an AI client (claude.ai, ChatGPT, Claude Code, Claude Desktop, Cursor, or anything that speaks the Model Context Protocol) talk to your Alchemist Cloud project tickets directly. From inside your assistant you can dispatch tickets, list and read their status, reply to a ticket that's paused waiting on your input, watch deploys, read your deployed app's errors, check costs, browse the project's repo, run read-only queries against the project database, and export files -- all without leaving the conversation. > **Naming note:** this is a dedicated server for **Alchemist Cloud** > (project/ticket automation), separate from the [Chipp MCP > server](/docs/guides/chipp-mcp-server) (which manages Chipp *apps* -- > system prompt, knowledge, custom actions) and separate from the in-product > "Alchemist" chat assistant you talk to inside the dashboard. If you > previously connected an MCP client to the plain-named "Alchemist" server, > your connection keeps working unchanged -- the endpoint and auth are the > same, only the display name was clarified. The server speaks Streamable HTTP at **`https://build.chipp.ai/alchemist-api/api/mcp`**. There are two ways to connect, depending on what your client supports: - **OAuth** -- for hosted connectors whose "add connector" dialog offers only a URL (claude.ai custom connectors, ChatGPT). You paste the URL and approve a browser consent screen; there's no key to copy. Access is scoped to *you* (your user), so it reaches every project you own or are a member of. - **API key** -- for clients that let you set an `Authorization` header (Claude Code, Claude Desktop, Cursor). Access is scoped to your *tenant*. Either way you only ever see your own projects, tickets, and data. ## Option A -- OAuth (claude.ai, ChatGPT) Use this for hosted connectors whose dialog only takes a URL. In claude.ai: **Settings → Connectors → Add custom connector**. 1. Paste the server URL: **`https://build.chipp.ai/alchemist-api/api/mcp`** 2. Leave **OAuth Client ID / Client Secret blank** -- the connector registers itself automatically (Dynamic Client Registration). Those fields are only for pre-registered clients, which you don't need. 3. Click **Add**. A browser window opens an Alchemist consent screen -- sign in to your dashboard if prompted, then **Approve**. The connector is now live. No API key is involved. Disconnect any time from your client's connector settings (that revokes the access immediately). ## Option B -- API key (Claude Code, Claude Desktop, Cursor) These clients send a bearer token, so they use a tenant API key. > **Unified endpoint:** with an `alch_` API key you can also point your client > at **`https://build.chipp.ai/mcp`** (the same URL as the > [Chipp MCP Server](/docs/guides/mcp/)). The server routes by key type, so one > URL works for both products; the `alchemist-api` URL below remains fully > supported. > **Note:** **Already connected to the Chipp MCP Server?** Check two things: your org's > plan must be STUDIO_PRO, ENTERPRISE, or an active Chipp Executive plan, and > your org must have already connected Alchemist Cloud (**Settings → Alchemist > Cloud**). If both are true, your existing Chipp session (OAuth or an API > key, `chipp_at_*` / `chipp_sk_*`) on `https://build.chipp.ai/mcp` already has > every tool on this page, tickets, database access, repo search, release > control, billing, all of it. You do not need a separate `alch_` key just to > reach this catalog. Mint one only if you need a credential that is not tied > to your personal Chipp login: a tenant-wide key for headless automation, or > a URL for an OAuth hosted connector (claude.ai, ChatGPT) that does not speak > Chipp's own OAuth. ### 1. Create an API key Mint a key on the **API Keys** page in the Alchemist tab sidebar (owners and admins only; see [API keys](/docs/guides/alchemist-api-keys)). The secret is shown once -- copy it immediately. You can revoke it at any time. ### 2. Point your client at the server **Claude Code** (one command): ``` claude mcp add --transport http alchemist https://build.chipp.ai/alchemist-api/api/mcp \ --header "Authorization: Bearer alch_your_key_here" ``` **Claude Desktop / Cursor** (config file): ```json { "mcpServers": { "alchemist": { "url": "https://build.chipp.ai/alchemist-api/api/mcp", "transport": "streamable-http", "headers": { "Authorization": "Bearer alch_your_key_here" } } } } ``` ## Tools **Why your client may list tools this guide does not document.** On this endpoint, `tools/list` returns the whole server registry rather than a filtered set, so a few operations tools show up in your client: `propose_data_operation`, `propose_script_operation`, `run_script_operation`, `propose_slack_invite`, and `request_credentials`. They are not usable from a tenant API key or an OAuth connection. This lane binds only your tenant and your user, and those tools need a project-scoped conversation session, so every call fails immediately with `no_session_bound` or `no_project_bound`. They are reachable only from the project bridge that Alchemist's own desktop and project-token clients use, the same one your project's own agent talks over, see [Adding Environment Variables and Secrets](/docs/guides/alchemist-environment-variables) for `request_credentials` from that side. Nothing is wrong with your setup; ignore them here and use the tools below. ### Tickets - **dispatch_ticket** -- create and dispatch a ticket. `kind` is `feature`, `fix`, `refactor`, `data_operation`, or `org_agent_construction`; there is no standalone read-only investigate mode (research runs as a node inside a ticket's own graph). Write the title + description as a complete, self-contained brief -- the platform plans and verifies its own work internally, without asking follow-up questions. Pass `depends_on` (an array of ticket UUIDs or `#N` references) to make the ticket wait until those parents succeed (DAG dependencies). - **propose_ticket_batch** -- draft several related tickets at once, with dependency edges between them, behind ONE approval instead of one approval per ticket. Each draft ticket carries a stable `node_id` you mint (never a real ticket id); a dependency can point at another draft in the same batch (`type: "node"`, `ref` = its `node_id`) or at an already-filed ticket (`type: "existing"`, `ref` = its key/UUID -- this is how you extend a chain you started earlier). Validates the whole graph up front (no cycles, every project accessible, every dependency names what it consumes, one cohesive outcome per ticket) and returns an approval card plus a `batch_proposal_id`. Nothing is created yet. - **dispatch_ticket_batch** -- file every ticket in a batch proposed by `propose_ticket_batch`. Who approves depends on how you connect (see [Who approves a batch](#who-approves-a-batch)). Only your own account's proposals can be dispatched. Returns a `scope_id` for following the batch. Safe to call again for the same `batch_proposal_id`: an already-dispatched batch returns the same created ticket keys instead of filing duplicates. - **wait_for_tickets** -- follow tickets live. Pass `scope_id` and/or `tickets`; the call blocks until one of them changes (or `timeout_seconds`, default 90, max 110) and returns `changes`, a `cursor` to pass back on the next call, and `all_terminal`. Worker heartbeats never count as changes. See [Following tickets live](#following-tickets-live). - **start_sandbox_change** -- queue a small code change directly onto a project's sandbox coding agent, instead of filing a ticket for it. Takes one `instruction` (plain language, written for an agent that has the repo open) and an optional `idempotency_key`. Use it for a change you can describe in a sentence or two; use `dispatch_ticket` for larger work that needs planning, review, and the full pipeline. The work runs asynchronously: the call returns as soon as the request is queued, and a human reviews the change in the project workspace before it merges. There is no project argument -- the change targets the project bound to the connection, so this tool only works on a project-scoped connection (a bare tenant API key has no project bound and the call is refused). **Opt-in per project, off by default:** the tool is only offered to projects that have turned it on in project settings (the project's **Settings** tab, **Agent code changes** switch). A project owner or an organization owner or admin can flip it; editors and viewers cannot. Everywhere else it is neither listed nor callable, and `dispatch_ticket` remains the way to request code work. - **resolve_sandbox_review** -- answer a sandbox change that is waiting for review. A queued change pauses before it merges so a human can look at the preview; this applies their answer. Takes the review's `message_id`, a `decision` of `approve` (let it land) or `request_changes` (send it back), and optional `feedback` passed to the agent verbatim. Answering a review that was already resolved, in the project workspace or by the review timeout, is a safe no-op rather than an error. Same project-scoped connection requirement as `start_sandbox_change`, and gated by the same per-project opt-in -- the two are enabled together, so a project that can start a change can also answer its review. - **list_tickets** -- recent tickets, optionally filtered by project, status, `ids`, `scope_id`, or `updated_since` (pass the previous response's `asOf`). - **get_ticket** -- one ticket by UUID or number (`#42`). Its `result` field (`result_version: 1`) is the stable, machine-readable outcome: branch, head sha, recorded commit shas, outcome, summary, contract items, verification gaps, open questions, and cost from the credit ledger. - **get_ticket_contract** -- the ticket's contract items (its negotiated done-checklist), each with a verification state: `verified`, `not_verified`, or `not_recorded` (in the contract but never graded). Call this before saying a ticket fixes or covers something: `get_ticket` answers status, this answers coverage. - **get_ticket_audit** -- the agent's per-turn narration across all nodes in the ticket's graph. - **get_ticket_reports** -- durable per-phase execution reports and the final completion summary. - **get_scope_graph** -- the dependency graph and live progress rollup for a multi-ticket scope (`depends_on` DAG). Every node you can access carries the same `result` object as `get_ticket`. - **update_ticket** -- edit a not-yet-started ticket's title, body, or kind. - **cancel_ticket** / **retry_ticket** -- stop or re-run a ticket. - **reply_to_ticket** -- answer a ticket that's paused `awaiting_input` (the agent asked a question mid-build -- an ambiguity, a missing credential). Relay the human's answer; a continuation ticket resumes the work automatically. Never paste a secret value here -- if the agent asked for a credential, use the secure submission link from its question. ### Who approves a batch - **Chipp API key** (Claude Code, scripts): your `dispatch_ticket_batch` call is the approval. No person taps anything. - **OAuth** (claude.ai, ChatGPT, desktop connectors), a Chipp developer key (`chipp_sk_*`) on `https://build.chipp.ai/mcp`, a signed-in session, or an agent filing tickets from a Chipp app's chat (web chat, Slack, and the other channels): the assistant cannot approve. A person approves the whole batch once in Chipp. Open the Chipp Builder and ask the assistant to "dispatch ticket batch ``". It shows one card for the whole batch, with the ticket count, the projects, and the full ticket list collapsed. One Approve tap files every ticket; no ticket asks again, whether the batch has 3 tickets or 80. Until then, `dispatch_ticket_batch` files nothing and returns `ok: false` with `code: "BATCH_AWAITING_APPROVAL"` and where to approve. After the approval, call it again with the same `batch_proposal_id` to get the `scope_id`. - **A host that shows views** (see [Views in chat](#views-in-chat-mcp-apps)): the person can also approve right in the conversation, with **Approve all** on the batch card. ### Following tickets live A Claude Code session can file a batch and watch it progress, then read a structured result per ticket: 1. `propose_ticket_batch`, then `dispatch_ticket_batch`. Keep the `scope_id`. With an API key the dispatch call is the approval. 2. Start a background Monitor on the tickets stream. Put your key in an environment variable first; never paste it into the chat. ```bash curl -sN -H "Authorization: Bearer $CHIPP_API_KEY" \ "https://build.chipp.ai/alchemist-api/api/mcp/tickets/stream?scope_id=" \ | grep --line-buffered '^data: ' ``` Each line is one JSON event: `snapshot`, `status`, `phase`, `summary`, `awaiting_input` (with `question` and `request_id`), `terminal` (with `outcome` and a one-line `summary`), and finally `done`, after which the stream closes. Every event has a `cursor`; reconnect with `&cursor=` to resume without repeats. `tickets=,` works in place of `scope_id`. With a Chipp credential (`chipp_sk_*` or `chipp_at_*`) use `https://build.chipp.ai/mcp/tickets/stream` with the same query; it streams your org's tickets with the same limits. If you connect over OAuth and cannot run a Monitor, call `wait_for_tickets` in a loop instead; it is the same feed. One stream follows a whole scope (up to 200 tickets). A workspace can hold 20 open streams and `wait_for_tickets` calls at once; past that the server answers 429. A stream that stays open for 4 hours sends a `reconnect` event with a cursor and closes; start it again with that cursor. 3. On `awaiting_input`, answer with `reply_to_ticket` and the event's `request_id`. 4. After `done`, call `get_scope_graph` and read each node's `result`. ### Views in chat (MCP Apps) Hosts that support MCP Apps (the `io.modelcontextprotocol/ui` extension) show some tool results as small interactive views inside the conversation. Other clients, Claude Code included, get the same tools with the same text results and no view. | Tool | View | |------|------| | `propose_ticket_batch` | An approval card: how many tickets, which projects, the titles, and one **Approve all** button. | | `dispatch_ticket_batch`, `get_scope_graph` | A live dashboard of every ticket in the batch, with status, cost, and dependencies. | | `get_ticket_graph` | The agents working on one ticket, with spend against budget for each. | **Approve all** records your approval of the whole batch (the same approval the Chipp Builder card gives) and then asks the assistant to dispatch it. The button calls `approve_ticket_batch`, a tool only the view can call: the server lists it only for a client that declared MCP Apps support, and the host keeps it away from the model. It needs a signed-in Chipp account (an API key session dispatches its own batch and needs no approval), it only approves a batch in your own workspace, and a second click changes nothing. The dashboard and the agent graph update themselves through `wait_for_tickets`, so an open view counts toward the 20 open watches above. A view stops updating after 30 minutes; click **Resume live updates** to continue. ### Projects and deploys - **list_projects** -- your projects, with deploy status and public URL. - **get_project** -- one project, with its latest deploy and a cost breakdown. - **list_deploys** -- recent deploys for a project, with failure reasons. - **create_project** -- create a new project from a template (provisions the GitHub repo, initial deploy, and public URL; returns immediately, the deploy runs async -- poll `get_project` / `list_deploys` for build progress). - **get_deploy_gate_status** -- whether a project's deploy gate ("deploy trains") has work piling up: the gate mode, when it last actually released, how many contributions are currently held, and a live preview of the release notes / QA checklist a release would generate right now. Check this before proactively suggesting a deploy. - **trigger_deploy** -- release everything currently held behind a manual or scheduled deploy gate (same action as "Deploy now" in the dashboard). No-ops cleanly when the gate is continuous or nothing is pending. - **set_project_feature** -- turn a built-in feature of a project on or off. Every project ships two, switched off until you turn them on: `api` (API keys and paid `/api/v1` routes) and `mcp` (an MCP server at `/api/mcp` with OAuth and paid tools). Both can be on at once. No code change: the live build restarts with the new setting. `get_project` shows which are on. ### Production errors - **get_project_errors** -- recent error logs from a project's live app (pick a time window and an optional substring filter). - **get_alert_status** -- whether the error-investigation agent is currently working an alert on a project, and how often alerts have recurred. - **get_env_status** -- whether the project's production deployment is missing any required environment variables (from its startup env-validation logs; presence status only, never values). - **get_project_logs** -- read recent logs from a project's deployed app: pick a time window (5m-7d), a level (`error`/`warn`/`info`/`all`), and an optional substring or regex filter. Curated query, capped at 500 lines. ### Billing - **get_credit_balance** -- your current credit balance. - **get_project_cost** / **get_ticket_cost** -- cost breakdowns by project or ticket (LLM, sandbox, pod, storage). ### Repo access - **read_repo_file** -- read a single file from the project's GitHub repo (at the HEAD of the default branch). - **read_imported_repo_file** -- read one file from the GitHub repository the builder imported and confirmed for this project (the "rebuild an existing app" flow), not the project's own generated repo. Returns `not_found` until a GitHub import has been confirmed; files over ~512KB come back with `truncated: true` and empty content. - **list_repo_dir** -- list the entries in a repo directory (capped at 500). - **search_repo** -- case-insensitive literal substring search across the repo. ### Database - **inspect_schema** -- read the project database schema. Columns holding secrets are masked out. - **query_database** -- run a single read-only SQL query (SELECT / CTE only) against the project database. Writes and DDL are rejected at the connection level. ### Email ingestion - **provision_email_ingestion** -- set up the inbound email pipeline for a project: mints the ingest credential, creates the MX record and inbound mail server, and wires deliveries to the project's `/api/ingest/email` route. Idempotent; re-run to repair drift. - **get_email_ingestion_status** -- the project's ingest address and provisioning health (never returns the token). - **deprovision_email_ingestion** -- tear the pipeline down (the dormant ingest route stays safe; re-provisioning reuses the credential). ### Outbound mailbox - **set_project_outbound_mailbox** -- configure a project's custom outbound mailbox: a real mailbox on the customer's own mail provider (SMTP credentials), so the project's agent sends and is addressed as that real mailbox instead of the platform default. - **get_project_outbound_mailbox_status** -- a project's custom outbound mailbox status: host, port, username, whether a password is set, and a preview of the resolved From header. Never returns the password. ### File delivery - **export_csv** -- build a CSV from `{ columns, rows }`, store it in private R2, and return a short-lived signed download URL. - **deliver_file** -- upload arbitrary bytes to private R2 and return a short-lived signed download URL. ### Incident diagnostics - **what_changed** -- correlate recent deploys against the error rate around them, the first question in any incident ("did this start after a deploy?"). Returns each deploy that completed in the window with the error count in the equal-length span before and after it, flagging the ones where errors rose. - **watch_deploy** -- watch a deploy settle and return a regression verdict plus the exact rollback target, comparing the error rate after it against the equal-length span before. - **get_runtime_health** -- read a managed project's pod state: replica readiness, restart counts, crashloops, OOMKills, and pods stuck Pending. A pod that crashes before serving traffic writes no application logs, so this covers the blind spot **get_project_errors** cannot see. - **get_migration_status** -- compare the migrations recorded as applied on the live database against the migration files in the repo, and report which are pending. Use it when a deploy succeeded but the app errors on a missing column or table. - **get_user_journey** -- reconstruct one end user's timeline: their Chipp Insights beacon events (pageviews, identify, client-side errors) merged with server-side error lines mentioning them, oldest first. This is the support-ticket tool: aggregate analytics cannot answer "what happened to THIS person". ### Release control Platform releases govern the self-hosted project; project deploys govern a customer project. Rollback-shaped actions are deliberately ungated -- they are the recovery path, and they are reversible and audited. - **get_platform_release_state** -- read the current mode (`auto` = every push deploys on the next train window, `manual` = builds publish but hold) and the desired-state pointer. - **set_platform_release_mode** -- switch between `auto` and `manual`. Switching to manual is a pause, and is allowed freely. - **list_platform_releases** -- recent platform releases, newest first: git sha, status (`candidate` / `promoted` / `deployed` / `superseded` / `rolled_back`), commit subjects, and operator notes. - **promote_platform_release** -- promote a release to production, the same action as "Deploy now" on the Releases tab. Moves the desired-state pointer; the reconciler applies it. - **rollback_platform_release** -- move the desired-state pointer back to a previously deployed release. Ungated and available in any mode. - **list_platform_release_events** -- the release audit trail (published / promoted / rollback / deployed / superseded / mode_changed), newest first. Answers "who moved the pointer, when, and why". - **get_project_release_status** -- a project's rollback-relevant deploy state: whether it is pinned, and which recent deploys are recalled. - **rollback_project_deploy** -- roll a project back to a previously completed deploy by re-applying its built image, and pin the project so nothing rolls forward past it until cleared. - **clear_release_pin** -- remove that pin so normal forward deploys resume. - **recall_deploy** -- mark a deploy known-bad so it can never be chosen as a rollback target again. If the recalled deploy is the live one, a rollback to the newest non-recalled completed deploy is queued automatically. - **clear_recall** -- un-mark a previously recalled deploy, when the recall turned out to be a misdiagnosis. - **get_ci_run_log** -- read the REAL failed GitHub Actions job log for the project's repo: which jobs failed, the exact step that failed, and a redacted tail of each job's log. Call this FIRST when a deploy or CI run is red -- a release checkpoint's `detail` is a fixed placeholder line and tells you nothing. - **run_ticket_ci** -- starts a ticket's CI run in GitHub Actions (`ticket-ci.yml`): the whole type check plus the tests the branch touches, on the job branch's tip. Only the ticket's final verification node may call it, once per ticket; after a failure, a fix commit allows one more run. - **request_verification_session** -- signs a ticket's deployed-app verification node in to the project's deployed app as a dedicated verification account and checks `/api/auth/me`. Read-only by default; `mode: "mutate"` allows scoped writes that are reverted at node end. - **get_ticket_ci_result** -- the newest ticket CI run for a ticket: status, commit, run link, and on a finished run the type errors and failing tests. `wait_seconds` waits up to 240 seconds for the verdict. - **get_nightly_ci_report** -- last night's CI repair list for the project. Tickets no longer run type checks or unit tests; a nightly GitHub Actions job (`nightly-ci.yml`) runs the whole type check and test suite instead. Returns green or red, the sha and run link, counts, and the top type errors and failing tests with file and line. Ask for it in your Daily Ping and assign the repairs with `dispatch_ticket`. - **get_release_digest** -- today's suggested release: every ticket and commit landed but not yet deployed (fixes and features, the production errors each fix addresses, risk notes), the urgent production errors from the last 24 hours with where each one's fix stands, last night's CI status, and the link where a human approves the release. Nothing ships until someone clicks "Deploy now" there. Ask for it in your morning Daily Ping. ### Data-layer brief - **record_data_layer_brief** -- record the project's data-layer brief (what data the app stores and why). Recording after a confirmation resets the status to `recorded`, so a materially revised brief must be re-confirmed. - **confirm_data_layer_brief** -- confirm the recorded brief. This is the only thing that sets the status to `confirmed`, which is what opens the build gate. A confirmed brief that says "no data layer" is a valid outcome for a static app. ### Chipp agent widget Install the official Chipp chat widget into a project by AGENT NAME, so a project gets a real Chipp agent instead of a hand-rolled chat UI. - **find_chipp_agent_by_name** -- resolve a Chipp agent by human-readable name across every workspace the current builder can access. Returns `single` (safe to install directly), `multiple` (show a picker, then pass the chosen `application_id`), or no match. The discovery step; always call it first. - **install_chipp_agent_widget** -- install or update the widget for a project: resolves the agent by name (or by an `application_id` already confirmed via the picker), derives a theme from the project's own design tokens, and commits the official widget-v2 embed to the project's repo. - **get_chipp_agent_widget_status** -- report the project's CURRENT widget config (bound application, presentation mode/position/behavior/greeting, theme), or null if never installed. Call this BEFORE generating any new chat or AI-assistant UI: if a config exists, modify it through **install_chipp_agent_widget** instead of building a second integration. - **remove_chipp_agent_widget** -- uninstall the widget: supersedes the persisted config and deletes the generated files in one commit. Never touches the underlying Chipp agent or its conversations. Idempotent. ### Provider lookups Read-only checks against a project's OWN third-party provider account (currently the project's Stripe), so an agent can verify provider-side facts without ever seeing the credential. - **provider_lookup** -- run one enumerated read-only verb against the project's provider using its stored credential, resolved server-side: `list_webhook_endpoints`, `list_events`, `get_event`, subscription state, and `list_paid_checkout_sessions` (paid, completed sessions in a lookback window, default 48h, each with the buyer's email) for reconciling payments against provisioned members. Operator-granted per project; a project without the grant gets a clear "not enabled" result (do not retry). Responses are field-slimmed and secret-scrubbed, and `project_id` is tenant-checked. - **propose_provider_webhook** -- propose provisioning the project's own Stripe webhook endpoint with automatic signing-secret capture into the managed deployment. Approval-gated: files a proposal a project member approves from Slack or the dashboard; on approval the platform creates the endpoint, captures the signing secret (never shown to anyone), stores it as `STRIPE_WEBHOOK_SECRET`, and applies it to the deployment. Idempotent while a proposal is pending. Requires the operator write grant (`provider_broker_config.stripe.allowWrites`). ## Tool schemas (request/response reference) For the complete machine-readable request and response schemas for `dispatch_ticket`, `list_tickets`, and `get_ticket` -- including all field types, required/optional markers, annotated example payloads, and error code tables -- see the [Tickets MCP Tool Schemas](/docs/guides/alchemist-mcp-tickets-schemas) reference page. ## Notes - Reads are curated and bounded. The one SQL surface, **query_database**, is read-only (SELECT / CTE only, writes and DDL rejected) and tenant-scoped; there is no raw log-query tool. Every tool returns a structured result scoped to your tenant. - An OAuth connection (Option A) is scoped to your user and uses short-lived tokens that refresh automatically; revoke it by removing the connector in your client. An API key (Option B) is scoped to your tenant and stops working the instant you revoke it on the Alchemist **API Keys** page. - An API key authenticates any HTTP call to the platform API, not just MCP. - This page is also available as raw markdown at `https://build.chipp.ai/alchemist-api/api/docs/mcp-server.md`, and the whole doc set at `https://build.chipp.ai/alchemist-api/api/docs/llms-full.txt` -- point an AI agent at either. --- # Tickets MCP Tool Schemas Machine-readable request and response schemas for dispatch_ticket, list_tickets, and get_ticket, with field types, required/optional markers, and annotated example payloads. --- This page publishes the complete request and response schemas for the three primary Tickets MCP tools: `dispatch_ticket`, `list_tickets`, and `get_ticket`. Each section provides: - A **request schema** table (all parameters, types, required/optional). - An **annotated example request** in JSON. - A **response schema** table (all top-level and nested fields, types, required/optional). - An **annotated example response** in JSON. - An **error shapes** block (standard error envelope). For connection instructions (OAuth or API key), see [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server). --- ## Shared type: `Ticket` object All three tools return ticket summaries using the same `Ticket` object shape. Fields marked **required** are always present; fields marked **optional** are omitted when null rather than serialized as `null` except where noted. | Field | Type | Presence | Description | |---|---|---|---| | `id` | `string (uuid)` | required | Ticket UUID. Stable identifier for all MCP calls. | | `ticketRef` | `string` | required | Human-facing project-scoped ref, e.g. `ACME-42`. Falls back to `#` when the project key is not set. | | `projectSeq` | `integer` | required | Per-project sequence number (the N in `PROJ-N`). | | `projectId` | `string (uuid)` | required | Project this ticket belongs to. | | `title` | `string` | required | Ticket title as filed (may be redrafted server-side from the original dispatch). | | `status` | `string (enum)` | required | One of: `scoping`, `conversation`, `blocked`, `blocked_on_credits`, `credit_block_escalated`, `queued`, `running`, `awaiting_input`, `awaiting_budget_approval`, `awaiting_deploy`, `awaiting_approval`, `succeeded`, `failed`, `cancelled`, `timeout`, or `superseded`. | | `kind` | `string (enum)` | required | One of: `feature`, `fix`, `refactor`, `data_operation`, `org_agent_construction`. | | `currentPass` | `integer \| null` | required | Current pipeline pass number for legacy five-pass tickets. `null` for dynamic-graph tickets or not-yet-started tickets. | | `commitSha` | `string \| null` | required | Git commit SHA produced by this ticket, once landed. `null` until the land node completes. | | `branchName` | `string \| null` | required | Agent working branch (e.g. `agent/`). `null` until the ticket starts. | | `failureReason` | `string \| null` | required | Human-readable reason the ticket failed or timed out. `null` for non-failed tickets. | | `ticketSource` | `string \| null` | required | How the ticket was dispatched: `mcp`, `dashboard`, `cron`, etc. | | `createdAt` | `string (ISO 8601) \| null` | required | When the ticket was created. | | `startedAt` | `string (ISO 8601) \| null` | required | When the ticket started running. `null` if not yet started. | | `completedAt` | `string (ISO 8601) \| null` | required | When the ticket reached a terminal state. `null` if still in progress. | | `dependsOn` | `string[] (uuid[])` | required | Parent ticket UUIDs this ticket is blocked on. Empty array for independent tickets. | | `scopeId` | `string (uuid) \| null` | required | Scope batch ID for multi-ticket graphs dispatched together. `null` for standalone tickets. | | `requesterDisplayName` | `string \| null` | required | Display name of the human who dispatched the ticket, if captured. | | `requesterEmail` | `string \| null` | required | Email of the requester, if captured (used for `awaiting_input` notifications). | | `requesterAvatarUrl` | `string \| null` | required | Profile picture URL of the requester, if captured. | | `requesterChannel` | `string \| null` | required | Origin channel: `chipp_chat`, `slack`, `dashboard`, `mcp`, `api`, etc. `null` if not captured. | | `requesterExternalRef` | `string \| null` | required | Opaque back-reference to the originating context (Slack user + thread, session ID). Never a token/secret. | | `categoryId` | `string (uuid) \| null` | required | Ticket category ("epic") UUID. `null` if uncategorized. | | `categoryLabel` | `string \| null` | required | Category display label, e.g. `"Auth & Billing"`. `null` if uncategorized. Soft-deleted categories render as `" (deleted)"`. | | `categoryDeleted` | `boolean` | required | `true` when the category this ticket is tagged with has been soft-deleted. | --- ## `dispatch_ticket` Creates and dispatches a new ticket (agent run) for one of your projects. ### Request schema | Parameter | Type | Required | Description | |---|---|---|---| | `title` | `string (1-500 chars)` | **required** | Short ticket title. | | `project_id` | `string (uuid)` | required if `project` not set | Target project UUID. Takes precedence over `project`. | | `project` | `string` | required if `project_id` not set | Target project UUID or human-readable name (e.g. `"Acme Widgets"`). | | `description` | `string` | optional | Full brief / acceptance criteria. Write as a complete, self-contained spec. | | `kind` | `string (enum)` | optional | `feature` (default), `fix`, `refactor`, `data_operation`, or `org_agent_construction`. Auto-classified from title + description when omitted. | | `llm_routing_mode` | `string (enum)` | optional | `"cost"`, `"speed"`, or `"free"`. Model routing mode for this ticket. Omit to use the project's default (normally `"cost"`). A free-plan workspace always runs `"free"`. | | `pass_profile` | `string (enum)` | optional | `"auto"` (default), `"full"`, or `"minimal"`. Controls whether Security and Docs passes run. | | `depends_on` | `string[]` | optional | Parent ticket UUIDs or `#N` refs. Ticket waits until all parents succeed. **Requires `depends_on_reason`**. | | `depends_on_reason` | `string` | required when `depends_on` set | One sentence naming the landed output of the parent that this ticket consumes. | | `replaces` | `string (uuid or #N)` | optional | UUID or `#N` of a cancelled ticket this dispatch refiles. Dependents of the cancelled ticket are auto-repointed. | | `seed_from_ref` | `string` | optional | Branch name to seed this ticket's working branch from (for continuations/salvage of a prior failed ticket). | | `job_id` | `string (uuid)` | required when `attachments` non-empty | Pre-minted job UUID used with `mint_attachment_upload_url`. | | `attachments` | `AttachmentInput[]` | optional | Already-uploaded file references (never inline bytes). See `AttachmentInput` below. | | `confirm_no_attachments` | `boolean` | optional | Set `true` to acknowledge that a file/path reference in the ticket text is a repo path or URL, not an upload the agent needs to read. | | `conversation` | `ConversationTurn[]` | optional | Full conversation transcript leading up to this dispatch. Triggers server-side ticket drafting. | | `predrafted` | `boolean` | optional | Set `true` to file title/description verbatim, skipping server-side redrafting. Default `false`. | | `no_split` | `boolean` | optional | Set `true` to disable automatic ticket splitting even if the scope estimate exceeds the node threshold. | | `requester` | `RequesterInput` | optional | Who dispatched this ticket (display/notification only, not an authorization input). | | `category` | `string` | optional | Category name to assign this ticket to. Create-or-get by normalized name. | | `operation_key` | `string` | optional | Stable idempotency key for this dispatch node. Repeating the same key returns the original ticket instead of creating a duplicate. | | `override_duplicate` | `boolean` | optional | Set `true` to explicitly allow a near-duplicate dispatch after confirming the duplication is intentional. Audited. | #### `AttachmentInput` object | Field | Type | Required | Description | |---|---|---|---| | `key` | `string` | required | R2 key returned by `mint_attachment_upload_url`. | | `original_name` | `string` | required | Original filename (e.g. `"spec.pdf"`). | | `content_type` | `string` | required | MIME type (e.g. `"application/pdf"`). | | `size_bytes` | `number` | required | File size in bytes. | #### `RequesterInput` object | Field | Type | Required | Description | |---|---|---|---| | `display_name` | `string` | optional | Human display name. | | `email` | `string` | optional | Email address for notifications. | | `avatar_url` | `string` | optional | Profile picture URL. Must be `https://`. | | `channel` | `string (enum)` | optional | Origin channel: `chipp_chat`, `slack`, `dashboard`, `mcp`, `api`, `cron`, or `webhook`. | | `external_ref` | `string` | optional | Opaque origin pointer (e.g. Slack user + thread ref). Never a token/secret. | #### `ConversationTurn` object | Field | Type | Required | Description | |---|---|---|---| | `role` | `string (enum)` | required | `"user"`, `"assistant"`, or `"system"`. | | `content` | `string` | required | Message text. | ### Example request ```json { "title": "Add dark-mode toggle to the dashboard header", "project": "Acme Widgets", "description": "The dashboard header (web/src/routes/dashboard/Header.svelte) should have a sun/moon toggle that switches between light and dark Tailwind themes. Store the preference in localStorage. Acceptance: toggle renders on all breakpoints, preference persists on refresh, WCAG AA contrast passes on both themes.", "kind": "feature", "requester": { "display_name": "Ada Builder", "email": "ada@example.com", "channel": "mcp" }, "operation_key": "scope-abc123:node-0" } ``` ### Response schema | Field | Type | Presence | Description | |---|---|---|---| | `ticket` | `Ticket` | required | The dispatched (or idempotently replayed) ticket. See [Shared type: Ticket](#shared-type-ticket-object). | | `chain` | `ChainEntry[]` | optional | Present only when the drafting gate auto-split this ticket into a dependent chain. Ordered root-first. | | `repointed_dependents` | `RepointResult[]` | optional | Present only when `replaces` was supplied. Lists each formerly-blocked dependent that was auto-repointed onto this ticket. | | `duplicate` | `DuplicateInfo` | optional | Present only when this call was short-circuited into an existing ticket (idempotent replay or near-duplicate detection). | #### `ChainEntry` object | Field | Type | Presence | Description | |---|---|---|---| | `job_id` | `string (uuid)` | required | Ticket UUID of this chain member. | | `title` | `string` | required | Title of this chain member (as drafted). | | `ticket_ref` | `string` | required | Human-facing ref (e.g. `ACME-43`). | | `depends_on` | `string[]` | required | UUIDs of the chain members this one waits on. Empty for the root. | #### `RepointResult` object | Field | Type | Presence | Description | |---|---|---|---| | `ticket_id` | `string (uuid)` | required | Dependent ticket that was re-pointed (or failed re-point validation). | | `ok` | `boolean` | required | `true` if re-point succeeded; `false` if it was skipped. | | `reason` | `string` | optional | Present when `ok: false`. Explains why re-point was skipped (e.g. validation failure or concurrent operator action). | #### `DuplicateInfo` object | Field | Type | Presence | Description | |---|---|---|---| | `existing_job_id` | `string (uuid)` | required | UUID of the existing ticket this call was merged into. | | `existing_ticket_ref` | `string` | required | Ref of the existing ticket (e.g. `ACME-41`). | | `match_reason` | `string` | required | Human-readable explanation of why this was treated as a duplicate. | | `source` | `string (enum)` | required | `"operation_key"` (idempotent replay) or `"near_duplicate"` (content-similarity detection). | ### Example response ```json { "ticket": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "ticketRef": "ACME-42", "projectSeq": 42, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Add dark-mode toggle to the dashboard header", "status": "queued", "kind": "feature", "currentPass": null, "commitSha": null, "branchName": null, "failureReason": null, "ticketSource": "mcp", "createdAt": "2026-07-29T14:00:00.000Z", "startedAt": null, "completedAt": null, "dependsOn": [], "scopeId": null, "requesterDisplayName": "Ada Builder", "requesterEmail": "ada@example.com", "requesterAvatarUrl": null, "requesterChannel": "mcp", "requesterExternalRef": null, "categoryId": null, "categoryLabel": null, "categoryDeleted": false } } ``` **Example with auto-split chain** (when the ticket is large enough to split): ```json { "ticket": { "id": "a1b2c3d4-0000-0000-0000-000000000001", "ticketRef": "ACME-43", "projectSeq": 43, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Phase 1: Add dark-mode toggle to the dashboard header", "status": "queued", "kind": "feature", "currentPass": null, "commitSha": null, "branchName": null, "failureReason": null, "ticketSource": "mcp", "createdAt": "2026-07-29T14:00:05.000Z", "startedAt": null, "completedAt": null, "dependsOn": [], "scopeId": null, "requesterDisplayName": "Ada Builder", "requesterEmail": "ada@example.com", "requesterAvatarUrl": null, "requesterChannel": "mcp", "requesterExternalRef": null, "categoryId": null, "categoryLabel": null, "categoryDeleted": false }, "chain": [ { "job_id": "a1b2c3d4-0000-0000-0000-000000000001", "title": "Phase 1: Add dark-mode toggle to the dashboard header", "ticket_ref": "ACME-43", "depends_on": [] }, { "job_id": "a1b2c3d4-0000-0000-0000-000000000002", "title": "Phase 2: Persist theme preference and add E2E tests", "ticket_ref": "ACME-44", "depends_on": ["a1b2c3d4-0000-0000-0000-000000000001"] } ] } ``` --- ## `list_tickets` Lists recent tickets for your tenant, newest first. ### Request schema | Parameter | Type | Required | Description | |---|---|---|---| | `project_id` | `string (uuid)` | optional | Filter to one project. | | `status` | `string (enum)` | optional | Filter by status: `scoping`, `conversation`, `blocked`, `blocked_on_credits`, `credit_block_escalated`, `queued`, `running`, `awaiting_input`, `awaiting_budget_approval`, `awaiting_deploy`, `awaiting_approval`, `succeeded`, `failed`, `cancelled`, `timeout`, or `superseded`. | | `category` | `string` | optional | Filter by category name (case/whitespace-insensitive). Requires `project_id`. | | `category_id` | `string (uuid)` | optional | Filter by exact category UUID. | | `limit` | `integer (1-100)` | optional | Max results to return. Default `20`. | ### Example request ```json { "project_id": "11111111-1111-4111-8111-111111111111", "status": "running", "limit": 5 } ``` ### Response schema | Field | Type | Presence | Description | |---|---|---|---| | `tickets` | `Ticket[]` | required | Array of ticket summaries, newest first. See [Shared type: Ticket](#shared-type-ticket-object). Empty array when none match. | | `count` | `integer` | required | Number of tickets returned (always `tickets.length`; bounded by `limit`). | ### Example response ```json { "tickets": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "ticketRef": "ACME-42", "projectSeq": 42, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Add dark-mode toggle to the dashboard header", "status": "running", "kind": "feature", "currentPass": null, "commitSha": null, "branchName": "agent/a1b2c3d4-e5f6-7890-abcd-ef1234567890", "failureReason": null, "ticketSource": "mcp", "createdAt": "2026-07-29T14:00:00.000Z", "startedAt": "2026-07-29T14:00:30.000Z", "completedAt": null, "dependsOn": [], "scopeId": null, "requesterDisplayName": "Ada Builder", "requesterEmail": "ada@example.com", "requesterAvatarUrl": null, "requesterChannel": "mcp", "requesterExternalRef": null, "categoryId": "f0f1f2f3-0000-0000-0000-000000000001", "categoryLabel": "UI Enhancements", "categoryDeleted": false } ], "count": 1 } ``` --- ## `get_ticket` Returns a curated status digest plus enriched detail for one ticket. This is the default tool for ticket status -- reach for `get_ticket_reports` (full pass-report text) or `get_ticket_graph` (per-node diagnostics) only when this response is not enough. ### Request schema | Parameter | Type | Required | Description | |---|---|---|---| | `ticket` | `string` | **required** | Ticket identifier: project-scoped ref (`ACME-42`), UUID, or legacy global number (`#42` or `42`). | ### Example request ```json { "ticket": "ACME-42" } ``` ### Response schema The response includes the base `Ticket` fields (see [Shared type: Ticket](#shared-type-ticket-object)) at the key `ticket`, plus the additional enriched fields below. | Field | Type | Presence | Description | |---|---|---|---| | `ticket` | `Ticket` | required | Base ticket summary. See [Shared type: Ticket](#shared-type-ticket-object). | | `turnsUsed` | `integer` | required | Total agent turns consumed across all nodes in this ticket so far. | | `inputTokens` | `integer` | required | Accumulated input tokens across all model calls. | | `outputTokens` | `integer` | required | Accumulated output tokens across all model calls. | | `autoMergeStatus` | `string \| null` | required | Auto-merge status (`"merged"`, `"conflicts"`, etc.) or `null`. | | `creditBlockCount` | `integer` | required | Number of times this ticket has been blocked on credits since the last real top-up. Nonzero means a credit disagreement is cycling. | | `graphAmbientInterruptCount` | `integer` | required | Number of ambient-interruption requeues consumed. | | `graph` | `GraphSummary` | optional | Compact graph summary. Present for dynamic-graph tickets; absent for legacy five-pass tickets. | | `salvageNote` | `string` | optional | Present when the ticket is in a terminal failed/cancelled/timeout state and a checkpoint branch exists. Describes the branch/commit and the resume path (use `retry_ticket`). | | `completionSummary` | `string \| null` | required | Terminal digest written by the platform at completion. `null` for in-progress or not-yet-started tickets. | | `latestPhaseSummary` | `string` | optional | In-progress digest from the most recent pass. Absent for not-yet-started tickets. | | `outcome` | `string (enum)` | required | `fully_verified`, `implementation_succeeded`, `partially_verified`, `failed`, `timeout`, or `in_progress`. | | `deferredItems` | `OutcomeItem[]` | required | Items the agent explicitly deferred to a human or a follow-up ticket. Empty array when none. | | `verificationGaps` | `ContractItem[]` | required | Contract assertions the verification pass could not confirm. Empty array when none. | | `partiallyVerifiedItems` | `ContractItem[]` | required | Contract assertions that passed partially but have an unresolved agent-work item. Empty array when none. | | `followUpRecommendations` | `OutcomeItem[]` | required | Non-blocking suggestions surfaced by the agent for future tickets. Empty array when none. | | `humanActionRequired` | `boolean` | required | `true` when at least one item in `humanActions` still needs a human to act. | | `humanActions` | `string[]` | required | Ordered list of required next steps a human must perform. Empty array when none. | | `dependsOnTickets` | `DependencyRef[]` | optional | This ticket's parent tickets (bounded, omitted when empty). | | `followOnTickets` | `DependencyRef[]` | optional | Direct child tickets waiting on this one (bounded, omitted when empty). | #### `GraphSummary` object | Field | Type | Presence | Description | |---|---|---|---| | `origin` | `string (enum)` | required | How the graph was planned: `"dynamic"` (dispatch-time planned), `"five_pass_v1"` (legacy fixed pipeline). | | `status` | `string (enum)` | required | Graph-level rollup: `"ready"`, `"running"`, `"succeeded"`, `"failed"`, `"cancelled"`. | | `nodeCount` | `integer` | required | Total number of nodes materialized in the graph (including completed nodes). | | `nodes` | `GraphNodeRef[]` | required | Compact node list (capped at 20). | #### `GraphNodeRef` object | Field | Type | Presence | Description | |---|---|---|---| | `ref` | `string` | required | Node ref within the graph (e.g. `"implement-1"`, `"review-1"`). | | `kind` | `string (enum)` | required | Node kind: `plan`, `contract`, `research`, `investigate`, `implement`, `docs`, `integration`, `review`, `security`, `verification`, `qa_authoring`, `reconcile`, `merge_repair`, `land`, `deploy_verify`. | | `status` | `string (enum)` | required | Node status: `queued`, `running`, `succeeded`, `failed`, `cancelled`, `skipped`, `awaiting_input`, `blocked`. | #### `OutcomeItem` object (used in `deferredItems`, `followUpRecommendations`) | Field | Type | Presence | Description | |---|---|---|---| | `text` | `string` | required | The deferred item or recommendation, as plain text. | | `source` | `string` | required | Which pass/report surfaced this item, or `"derived"` for a pre-migration ticket. | #### `ContractItem` object (used in `verificationGaps`, `partiallyVerifiedItems`) | Field | Type | Presence | Description | |---|---|---|---| | `assertion` | `string` | required | The specific contract assertion that was not fully verified. | | `evidence` | `string` | optional | Evidence the verification node collected (what it checked and what it found). | | `source` | `string` | required | Which pass/report surfaced this item, or `"derived"`. | #### `DependencyRef` object (used in `dependsOnTickets`, `followOnTickets`) | Field | Type | Presence | Description | |---|---|---|---| | `ticketRef` | `string` | required | Human-facing ref of the related ticket (e.g. `ACME-41`). | | `title` | `string` | required | Title of the related ticket. | | `status` | `string (enum)` | required | Current status of the related ticket. | ### Example response (succeeded ticket) ```json { "ticket": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "ticketRef": "ACME-42", "projectSeq": 42, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Add dark-mode toggle to the dashboard header", "status": "succeeded", "kind": "feature", "currentPass": null, "commitSha": "abc123def456", "branchName": "agent/a1b2c3d4-e5f6-7890-abcd-ef1234567890", "failureReason": null, "ticketSource": "mcp", "createdAt": "2026-07-29T14:00:00.000Z", "startedAt": "2026-07-29T14:00:30.000Z", "completedAt": "2026-07-29T14:18:45.000Z", "dependsOn": [], "scopeId": null, "requesterDisplayName": "Ada Builder", "requesterEmail": "ada@example.com", "requesterAvatarUrl": null, "requesterChannel": "mcp", "requesterExternalRef": null, "categoryId": "f0f1f2f3-0000-0000-0000-000000000001", "categoryLabel": "UI Enhancements", "categoryDeleted": false }, "turnsUsed": 42, "inputTokens": 180000, "outputTokens": 24000, "autoMergeStatus": "merged", "creditBlockCount": 0, "graphAmbientInterruptCount": 0, "graph": { "origin": "dynamic", "status": "succeeded", "nodeCount": 6, "nodes": [ { "ref": "plan-1", "kind": "plan", "status": "succeeded" }, { "ref": "contract-1", "kind": "contract", "status": "succeeded" }, { "ref": "implement-1", "kind": "implement", "status": "succeeded" }, { "ref": "review-1", "kind": "review", "status": "succeeded" }, { "ref": "verification-1", "kind": "verification", "status": "succeeded" }, { "ref": "land-1", "kind": "land", "status": "succeeded" } ] }, "completionSummary": "Added a sun/moon toggle to `Header.svelte` that switches between light and dark Tailwind themes. Preference is persisted in `localStorage`. WCAG AA contrast verified on both themes. Merged to staging at abc123def456.", "outcome": "fully_verified", "deferredItems": [], "verificationGaps": [], "partiallyVerifiedItems": [], "followUpRecommendations": [ { "text": "Consider syncing the theme preference with the user's OS-level prefers-color-scheme media query in a follow-up.", "source": "review-pass-2" } ], "humanActionRequired": false, "humanActions": [] } ``` ### Example response (failed ticket with salvage note) ```json { "ticket": { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "ticketRef": "ACME-43", "projectSeq": 43, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Migrate user preferences to new schema", "status": "failed", "kind": "data_operation", "currentPass": null, "commitSha": null, "branchName": "agent/b2c3d4e5-f6a7-8901-bcde-f12345678901", "failureReason": "Migration dry-run detected 3 rows that would violate the NOT NULL constraint on preferences.theme. Manual review required before applying.", "ticketSource": "dashboard", "createdAt": "2026-07-29T15:00:00.000Z", "startedAt": "2026-07-29T15:00:30.000Z", "completedAt": "2026-07-29T15:12:10.000Z", "dependsOn": [], "scopeId": null, "requesterDisplayName": null, "requesterEmail": null, "requesterAvatarUrl": null, "requesterChannel": null, "requesterExternalRef": null, "categoryId": null, "categoryLabel": null, "categoryDeleted": false }, "turnsUsed": 18, "inputTokens": 72000, "outputTokens": 9000, "autoMergeStatus": null, "creditBlockCount": 0, "graphAmbientInterruptCount": 0, "completionSummary": null, "outcome": "failed", "salvageNote": "Checkpoint branch agent/b2c3d4e5-f6a7-8901-bcde-f12345678901 has 2 committed steps. To resume from this checkpoint, call retry_ticket with ticket id b2c3d4e5-f6a7-8901-bcde-f12345678901.", "deferredItems": [], "verificationGaps": [], "partiallyVerifiedItems": [], "followUpRecommendations": [], "humanActionRequired": true, "humanActions": [ "Review the 3 rows with null theme values in app.user_preferences and backfill a default before retrying the migration." ] } ``` ### Example response (awaiting input) ```json { "ticket": { "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "ticketRef": "ACME-44", "projectSeq": 44, "projectId": "11111111-1111-4111-8111-111111111111", "title": "Integrate Stripe Checkout for the Pro plan upgrade", "status": "awaiting_input", "kind": "feature", "currentPass": null, "commitSha": null, "branchName": "agent/c3d4e5f6-a7b8-9012-cdef-123456789012", "failureReason": null, "ticketSource": "mcp", "createdAt": "2026-07-29T16:00:00.000Z", "startedAt": "2026-07-29T16:00:30.000Z", "completedAt": null, "dependsOn": [], "scopeId": null, "requesterDisplayName": "Ada Builder", "requesterEmail": "ada@example.com", "requesterAvatarUrl": null, "requesterChannel": "mcp", "requesterExternalRef": null, "categoryId": null, "categoryLabel": null, "categoryDeleted": false }, "turnsUsed": 11, "inputTokens": 44000, "outputTokens": 5500, "autoMergeStatus": null, "creditBlockCount": 0, "graphAmbientInterruptCount": 0, "completionSummary": null, "latestPhaseSummary": "Implement node running: Stripe webhook endpoint scaffolded; awaiting the Stripe webhook secret to wire the signature-verification middleware.", "outcome": "in_progress", "deferredItems": [], "verificationGaps": [], "partiallyVerifiedItems": [], "followUpRecommendations": [], "humanActionRequired": true, "humanActions": [ "Provide the Stripe webhook signing secret via the secure link in the agent's question. Do not paste the secret value into the chat -- use the secure submission link." ] } ``` --- ## Error shapes All three tools return errors in the same JSON-RPC error envelope. The `data` field carries a structured object with a machine-readable `code`. ```json { "jsonrpc": "2.0", "id": 1, "error": { "code": -32600, "message": "Human-readable explanation of the error.", "data": { "code": "MACHINE_READABLE_CODE", "statusCode": 400 } } } ``` ### Common error codes | `data.code` | `statusCode` | Triggered by | |---|---|---| | `NOT_FOUND` | 404 | Ticket or project UUID does not exist, or belongs to a different tenant. The error message is the same regardless of which case applies (tenant isolation -- no existence leak). | | `MISSING_JOB_ID` | 400 | `dispatch_ticket`: `attachments` non-empty but `job_id` not supplied. | | `ATTACHMENT_REFERENCE_WITHOUT_ATTACHMENTS` | 400 | `dispatch_ticket`: ticket text references a filename but `attachments` is empty and `confirm_no_attachments` was not set. | | `DEPENDS_ON_REASON_REQUIRED` | 400 | `dispatch_ticket`: `depends_on` supplied without a `depends_on_reason` of at least 10 characters. | | `REPLACES_NOT_CANCELLED` | 400 | `dispatch_ticket`: `replaces` refers to a ticket that is not in the `cancelled` state. | | `INVALID_SEED_FROM_REF` | 400 | `dispatch_ticket`: `seed_from_ref` contains characters outside the allowed branch-name charset. | | `INVALID_KIND` | 400 | `dispatch_ticket`: `kind` is not one of the allowed enum values. | | `INVALID_PASS_PROFILE` | 400 | `dispatch_ticket`: `pass_profile` is not one of the allowed enum values. | | `CATEGORY_FILTER_REQUIRES_PROJECT` | 400 | `list_tickets`: `category` filter supplied without `project_id`. | | `NOT_CANCELLABLE` | 409 | `cancel_ticket`: ticket is already in a terminal state. | | `UNAUTHENTICATED` | 401 | No valid `Authorization: Bearer alch_...` header, or the key has been revoked. | | `FORBIDDEN` | 403 | Valid key but the caller does not have access to the referenced project. | ### Notes on `NOT_FOUND` The `NOT_FOUND` error is intentionally opaque: whether the ticket or project does not exist, or exists but belongs to a different tenant, the same error is returned. This prevents an authenticated caller from probing for UUIDs that belong to other tenants. --- ## See also - [Alchemist Cloud Tickets MCP](/docs/guides/alchemist-mcp-server) -- connection instructions, the full tool list (including `get_ticket_graph`, `get_ticket_reports`, `reply_to_ticket`, and the project/billing/database tools). - [Alchemist Tickets](/docs/guides/alchemist-tickets) -- ticket lifecycle, graph nodes, cancel/retry semantics. - [Alchemist Reports and Audit](/docs/guides/alchemist-reports-and-audit) -- per-node reports and the agent-turn audit trail. - [Alchemist API Keys](/docs/guides/alchemist-api-keys) -- how to create an `alch_` key and manage its lifecycle. --- # Alchemist: Agent Pipeline Configuration Set the routing mode and per-ticket budget cap that new tickets in a project start with. --- Every ticket runs as a graph of nodes, and each node kind runs on a fixed model chain (see **[Pipeline permutations](/docs/guides/alchemist-pipeline-permutations)**). There are no per-phase model pickers. The **Model preferences** panel, in the **Settings** tab of a project, sets the defaults new tickets start with. ## Routing mode **Routing mode (default for new tickets)** has two options: - **Cost-optimized** -- holds quality while optimizing for cost. This is the default. - **Fast and best** -- fastest strong models on the fastest providers, with no regard to cost. A ticket can pick the other mode when it is created. A node-level model pin in the ticket text is the only per-model override. ## Ticket budget cap **Default ticket budget cap** is the most a single ticket may spend before it pauses for your approval. Leave it blank, or click **Use platform default**, to use the platform default. The panel shows the effective cap and whether it comes from the platform default or your project override. A lower cap means more tickets pause for approval; a higher cap means fewer pauses but more unattended spend per ticket. ## Builder drafts The same panel sets **Sleep after this many idle minutes** for Builder sandboxes (default 15 minutes) and a **Monthly Builder budget**. --- # Alchemist: Pipeline Permutations Reference for the pipeline shapes a ticket can run through. --- A ticket runs as a graph of nodes (plan, implement, review, security, docs, investigate, and others). Each node kind runs on a fixed model chain chosen by the ticket's **routing mode**. There are no pipeline tiers and no per-phase model pickers. This page is the in-product target of the **Model preferences** panel's **Learn more** link. ## Routing modes - **Cost-optimized** (the default) -- holds quality while optimizing for cost. - **Fast and best** -- fastest strong models on the fastest providers, with no regard to cost. Free-tier organizations run every node on a free model set instead. Set the default mode for new tickets in the project's **Settings** tab, under **Model preferences**. A ticket can pick the other mode when it is created. ## Node kind to model In both Cost-optimized and Fast and best modes: - **Plan, review, security, verification, design, merge resolution** -- Claude Opus 5.5 at medium effort, with Claude Sonnet 5.5 as the retry. - **Implement, docs, investigate, reconcile, data operations** -- Claude Sonnet 5.5, with Claude Opus 5.5 at medium effort as the retry. - **The orchestrator that writes the graph** -- Claude Opus 5.5 at high effort, with Claude Sonnet 5.5 as the retry. A retry moves up the chain, never down. A node-level model pin written into the ticket text is the only per-model override. See **[Agent pipeline configuration](/docs/guides/alchemist-pipeline-configuration)** for the per-project settings. --- ============================================================ SECTION: Getting Started ============================================================ # The Alchemist Copilot The Alchemist copilot is your AI-powered assistant inside the Chipp app builder, used to configure published chat agents and manage your workspace. For the Alchemist autonomous software-development platform (tickets, agents, CI/CD delivery), see Alchemist Tickets and Alchemist Getting Started. --- import Callout from "../../../components/docs/Callout.astro"; The Alchemist is your AI-powered builder assistant, available everywhere in the Chipp platform. It can analyze your chatbot's conversations, configure app settings, generate content, manage knowledge sources, and more -- all through natural language. Think of it as a co-pilot that knows every feature in the platform and can operate them for you. > **Note:** "Alchemist" names two related things. This guide covers the **Alchemist copilot**: the chat panel inside the Chipp builder. The **Alchemist platform** is the autonomous development system at build.chipp.ai that builds and maintains full applications through tickets. For that, see [Alchemist Tickets](/docs/guides/alchemist-tickets) and [local development](/docs/guides/alchemist-local-development). ## Where to Find It The Alchemist panel appears in two places: - **Dashboard**: The panel on the main dashboard page operates in workspace mode. It has access to analytics across all your apps, can compare performance, and navigate you into any app's builder. - **App Builder**: When you're editing a specific app, the Alchemist panel has full access to that app's configuration. It can read and modify settings, knowledge sources, integrations, tags, and more. ## What It Can Do ### Conversation Analysis The most powerful use case: ask the Alchemist to analyze your chat logs and tell you how to improve your app. It will: 1. Sample recent conversations across different categories (short/abandoned, long/engaged, recent, random) 2. Spin up a dedicated analysis agent with a fresh context window focused entirely on your conversation data 3. Identify frustration patterns, knowledge gaps, error patterns, and what's working well 4. Return prioritized, actionable recommendations grounded in real conversation examples **Try asking:** - "Analyze my conversations and tell me how to improve this app" - "What are users struggling with?" - "Look at the last 7 days of chats and find knowledge gaps" After the analysis, the Alchemist can immediately act on its own recommendations -- updating your system prompt, adding knowledge sources, or configuring new features. ### Analytics & Insights Get instant answers about your chatbot's performance without navigating dashboards: | What you can ask | What it does | |-----------------|--------------| | "How many conversations did I have this week?" | Returns session counts, message volume, and trends | | "What are my users talking about?" | Samples recent first messages and clusters them by topic | | "Show me my top consumers" | Consumer report with engagement metrics, leads, and email collection | | "Which app is getting the most traffic?" | Per-app overview with chat counts and consumer counts | | "Search for conversations about refunds" | Full-text search across all chat messages | | "What tags are being triggered most?" | Tag distribution with percentages and sample messages | All analytics tools accept a date range (e.g., "last 7 days", "last 90 days") and can be filtered to a specific app. ### App Configuration The Alchemist can read and modify every aspect of your app's configuration: - **System prompt**: "Update the system prompt to be more friendly and add instructions for handling billing questions" - **Model selection**: "Switch this app to Claude Sonnet" - **Brand & styling**: "Set the primary color to dark blue and generate a logo" - **Knowledge sources**: "Add this URL as a knowledge source" or "Add these 5 URLs to the knowledge base" - **Custom actions**: "Create an HTTP action that calls my CRM API to look up customer info" - **Tags**: "Set up lead qualification tags for hot leads, cold leads, and support requests" - **Auth settings**: "Require users to log in before chatting" - **Voice settings**: "Enable voice mode with a professional female voice" - **Heartbeat**: "Set up a daily check-in message that asks users how their project is going" - **Publishing**: "Publish this app live" ### Content Generation Create visual assets and web content through conversation: - **Logos**: "Generate a logo for a fitness coaching chatbot" -- creates an AI logo and applies it - **Custom CSS themes**: "Design a dark mode theme with purple accents and rounded bubbles" -- generates and applies a full CSS theme via the Style Studio - **Landing pages**: "Build a landing page that explains what this chatbot does" -- creates a multi-page site via Chipp Sites - **Custom components**: "Create a pricing table component with three tiers" -- generates interactive HTML/CSS/JS components ### Integration Management Build and deploy integrations without writing code: - **MCP servers**: "Create an MCP server that connects to my project management API" - **Deploy & test**: "Deploy the integration and test the list_projects tool" - **OAuth setup**: Navigate to OAuth configuration flows when needed ### Marketplace & Templates Discover and use pre-built app blueprints and composable skills: - **Browse**: "Show me templates for customer support bots" - **Create from template**: "Create a new app from the Sales Closer template" - **Apply skills**: "Add the Empathetic Listener skill to this app" -- composable prompt modules that enhance your app ### Advanced Reasoning For complex questions, the Alchemist can think more deeply: - **Deep thinking**: Breaks down complex questions into structured reasoning steps. "Plan out how I should restructure my app to handle both sales and support." - **Deep research**: Spawns parallel web research agents to find authoritative information. "Research best practices for AI customer support bots in healthcare." ## Example Workflows ### "Improve my app" workflow This is the most common and most powerful workflow: **1.** Ask for analysis "Analyze my conversations and tell me what I should improve" **2.** Review the findings The Alchemist will present categorized issues: frustration patterns, knowledge gaps, error patterns, and what's working well. Each issue includes real conversation examples and a specific fix. **3.** Implement the fixes "Go ahead and add billing documentation to the knowledge base" or "Update the system prompt to handle refund requests." The Alchemist uses its builder tools to make the changes directly. **4.** Publish "Publish the app" to push the improvements live. ### New app setup workflow **1.** Create from template or scratch "Create a customer support bot for a SaaS product" or "Use the Sales Closer template" **2.** Configure "Set the system prompt to focus on helping users with onboarding and billing. The company is called Acme and we sell project management software." **3.** Add knowledge "Add these URLs as knowledge sources: docs.acme.com/faq, docs.acme.com/billing, docs.acme.com/getting-started" **4.** Brand it "Generate a logo and set the brand color to #2563EB" **5.** Publish "Publish the app" ### Cross-app analytics workflow From the dashboard, you can analyze performance across all apps: 1. "Which of my apps is getting the most conversations?" 2. "Show me the chat analytics for the last 30 days across all apps" 3. "What are the most common topics users ask about?" 4. "Open the Customer Support Bot so I can make changes" -- navigates you into the app builder with the Alchemist panel open ## Long Conversations When you work with the Alchemist for extended periods (building out a complex app, walking through analytics across many sessions, or chaining a long sequence of changes), the conversation history can grow large enough that the AI starts to lose focus on the most recent details. The Alchemist now handles this automatically with **server-side context compaction**. ### What you'll see in the chat Once a conversation gets long enough that summarization becomes worthwhile, you'll see: 1. A brief **"Compacting earlier conversation..."** indicator while the summary is being generated. 2. A **summary divider** that replaces the older messages, clearly labeled `Earlier conversation summary — N messages compacted` with the AI's own summary of what was done before. You can expand it to read the summary; the divider stays in place for the rest of the session. 3. The chat continues normally below the divider, with the most recent ~7 user/assistant exchanges kept verbatim. You don't need to do anything to trigger compaction. It runs in the background, transparently, the moment the conversation needs it. ### Recall: getting verbatim details back from the summary A summary is, by design, a lossy compression of what happened earlier. If you ever ask the Alchemist about something specific that lives in the summarized portion (an exact file path, a value it generated, a tool result, the wording of an earlier instruction), it has a tool called **`recall_earlier_conversation`** that searches the full pre-compaction history (preserved as a searchable archive scoped to your current session). You don't need to invoke this tool manually. The Alchemist decides when to use it based on your question. For example: - "What was that bot token we set up earlier?" → searches the archive, finds the verbatim mention - "Earlier you generated a logo, what was the prompt?" → pulls back the exact tool call - "Can you remind me what error we hit when we tried to deploy?" → returns the message snippet If the archive doesn't contain a match, the Alchemist will tell you so plainly rather than guess. ### Which models support it The native server-side compaction runs on Anthropic's reasoning models. The Alchemist's default (Claude Sonnet 5.5) is one of them, so most users get this behavior automatically. If your workspace has overridden the Alchemist model to a non-Anthropic option (GPT-5, Gemini, etc.), the Alchemist falls back to a similar built-in summarization step that produces the same divider and the same searchable archive; only the underlying mechanism differs. ### Tips for long sessions - **Trust the divider.** Once you see a compaction summary, the older messages still exist in the searchable archive. You haven't lost them; they're just no longer in the AI's active working memory. - **Be specific when recalling.** "What was the X we configured?" works better than "what did we do earlier?" because the recall tool uses keyword search. - **Start fresh if you switch contexts.** If you finish one task and want to start something completely unrelated, open the **More actions** menu in the Alchemist header and choose **New session**. A fresh context window is faster than working through a long compacted history when the topics don't relate. ## Dashboard Mode vs App Mode | Capability | Dashboard | App Builder | |-----------|-----------|-------------| | Analytics (all apps) | Yes | Yes (filtered to current app) | | Conversation analysis | Yes (any app) | Yes (current app) | | Browse templates | Yes | Yes | | Create app from template | Yes | Yes | | Read app config | After selecting an app | Automatic | | Modify app settings | After selecting an app | Automatic | | Generate logos, CSS, sites | After selecting an app | Automatic | | DOM interaction (uploads, OAuth) | After navigating to app | Yes | In dashboard mode, the Alchemist automatically calls **select_app** when it needs to work with a specific app. You can also tell it which app to work with: "Select my Customer Support Bot and update its system prompt." ## Tips - **Be specific**: "Add a knowledge source about our refund policy" is better than "improve my knowledge base" - **Chain requests**: The Alchemist maintains context, so you can say "Now also add one for the pricing page" after adding a knowledge source - **Use analysis first**: Before making changes, ask the Alchemist to analyze conversations. Data-driven improvements beat guesswork. - **Filter by date**: "Analyze conversations from the last 7 days" focuses on recent patterns. "Last 90 days" gives a broader picture. - **Focus your analysis**: "Analyze conversations with a focus on onboarding issues" tells the analysis agent to prioritize a specific area. > **Note:** The Alchemist is available on all plans. Some tools it uses (like custom CSS, voice cloning, or advanced integrations) may require specific plan tiers. --- # Choosing a Model How to select the best AI model for a published Chipp chat agent. Model selection applies to conversational agents -- one output type Alchemist supports. For non-chat workloads (APIs, backend services, data pipelines), the AI runs in the engineering pipeline, not the deployed software. --- Chipp supports multiple AI models from OpenAI, Anthropic, Google, and more. Each has different strengths, speeds, and costs. This guide helps you choose the right one. ## Quick Recommendations | Use Case | Recommended Model | |----------|-------------------| | General purpose | GPT-5.4, Claude Sonnet 4.6, or GPT-5.6 Terra | | Image analysis | Gemini 3.1 Pro, GPT-5.4, or Claude Sonnet 4.6 | | Complex reasoning / frontier work | o3, Claude Opus 4.8, GPT-5.5 Pro, or GPT-5.6 Sol | | Fast responses | Gemini 3.5 Flash, GPT-5 Mini, or Claude Haiku 4.5 | | Long documents | Gemini 3.1 Pro or GPT-4.1 (1M token context) | | Cost-sensitive / high-volume | Gemini 3.5 Flash, GPT-5 Nano, or GPT-5.6 Luna | ## Estimate Your Costs Use our calculator to estimate monthly AI costs based on your expected usage: ## Featured Models ### Best for General Purpose These models excel at a wide range of tasks including writing, coding, analysis, and conversation. ### Best for Speed When response time matters most, these models deliver near-instant results without sacrificing quality. ### Best for Reasoning For complex problem-solving, multi-step analysis, and tasks requiring deep thinking. ### Best Value for Long Documents Process entire codebases, legal contracts, or book-length content with massive context windows. ## Model Deep Dives ### OpenAI GPT-5.4 ### OpenAI GPT-5.6 Sol GPT-5.6 Sol is OpenAI's newest frontier model (also selectable via the `gpt-5.6` alias). Priced at $4/$20 per million tokens (OpenAI's current promotional rate; prompts over 272K tokens bill at $8/$30) with a 1M-token context window, it targets the same complex-reasoning and coding use cases as GPT-5.5 Pro and Claude Opus 4.8. See [Model Benchmarks](https://developers.openai.com/api/docs/models/gpt-5.6-sol) for official specs. ### OpenAI GPT-5.6 Terra GPT-5.6 Terra balances intelligence and cost at $2/$12 per million tokens, a general-purpose option priced below both GPT-5.4 ($2.50/$15) and GPT-5.6 Sol. ### OpenAI GPT-5.6 Luna GPT-5.6 Luna is OpenAI's most cost-efficient GPT-5.6 tier at $0.20/$1.20 per million tokens, aimed at high-volume, cost-sensitive workloads. ### Claude Sonnet 4.6 ### Gemini 3.1 Pro ### OpenAI o3 ### Claude Haiku 4.5 ### Gemini 3.5 Flash ## Cost-Effective Options If you're optimizing for cost, these models offer excellent value: ## Key Considerations ### Vision Support If your app analyzes images, choose a model with native vision support. Models without vision use a fallback that may be less accurate. **Vision-capable models:** - All GPT-4.1 and GPT-5.x variants, including the GPT-5.6 family (not o-series reasoning models) - All Claude models - All Gemini models **No vision support:** - OpenAI o-series (o1, o3, o4-mini, etc.) ### Response Speed Speed matters for user experience. Faster models keep conversations flowing naturally. **Fastest:** GPT-5 Nano, Claude Haiku 4.5, Gemini 3.5 Flash, GPT-5.6 Luna **Medium:** GPT-5.4, Claude Sonnet 4.6, GPT-5.6 Terra **Slower:** Claude Opus 4.8, o1, o3, GPT-5.6 Sol (reasoning takes time) ### Context Window For processing long documents, choose models with large context windows: **1M+ tokens:** GPT-4.1 variants, GPT-5.x variants (including GPT-5.6 Sol/Terra/Luna at 1.05M), Claude Opus 4.8, Claude Sonnet 4.6, all Gemini models **200k tokens:** Claude Haiku 4.5, OpenAI o-series Note: Chipp enforces a 128K runtime ceiling on the entire GPT-5.x family (including GPT-5.6) regardless of the published context window, to stay within OpenAI's Responses API's practical limits. ### Reasoning Quality For complex tasks requiring multi-step reasoning: **Best reasoning:** o3 Pro, Claude Opus 4.8, GPT-5.5 Pro, GPT-5.6 Sol **Very good:** GPT-5.4, Claude Sonnet 4.6, o3, o4-mini, GPT-5.6 Terra **Good:** GPT-5 Mini, Claude Haiku 4.5, Gemini 3.1 Pro, GPT-5.6 Luna ## HIPAA-Compliant Models Building a healthcare app? Chipp holds BAAs with Google (Gemini models) and Anthropic (Claude models, excluding Claude Fable). Choose one of these BAA-covered models for your app's chat. Enabling **HIPAA Compliance** in **Launch > Access** enforces authentication and session controls, but it does not itself restrict which chat model you can pick, so make sure you selected a covered model. See [HIPAA-Compliant Models](/docs/guides/hipaa-compliant-models) for the full breakdown and important caveats. ## Changing Your Model 1. Go to your app in the Chipp dashboard 2. Navigate to **Brain** > **Prompt** 3. Under **Chat Model**, select your preferred model 4. Your change saves automatically Changes take effect immediately for new conversations. ## Testing Different Models Not sure which model works best? Try these approaches: 1. **A/B testing**: Create two versions of your app with different models and compare user feedback 2. **Specific prompts**: Test your most common use cases with different models to see quality differences 3. **Speed vs. quality**: Start with a fast model, then upgrade if users need better responses ## Using with MCP You can manage AI models programmatically using the Chipp MCP Server, including AI-powered model recommendations. ### Available Tools | Tool | Description | |------|-------------| | `get_model` | Get current model for an app | | `update_model` | Change the AI model for an app | | `list_available_models` | List all available AI models | | `recommend_model` | Get AI-powered model recommendations | ### Example Prompts ``` "What model is my FAQ bot using?" "Switch my support bot to GPT-5.4" "Which model would you recommend for my customer service app?" "List all available models with their pricing" ``` ### Workflow: AI-Powered Model Selection ``` You: Recommend a model for my customer support bot that needs to be fast and handle simple FAQ questions AI: [Calls recommend_model with priority="speed"] Based on your use case, I recommend: 1. **Gemini 3.5 Flash** (Best choice) - Very fast responses (~1.5s) - Cost: $1.50/M input, $9.00/M output - Great for FAQ and simple queries 2. **GPT-5 Nano** (Budget option) - Fastest response time - Cost: $0.05/M input, $0.40/M output - Good for high-volume, simple tasks Want me to update your app to use Gemini 3.5 Flash? You: Yes, update it AI: [Calls update_model] Updated FAQ Bot to use Gemini 3.5 Flash. Changes take effect for new conversations. ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- # Skills & Templates Understand the difference between templates and skills, and how to use them to build better AI agents. --- ## What are Templates? Templates are **full AI agent blueprints**: pre-built configurations that include a system prompt, model selection, suggested messages, and sometimes required integrations. When you use a template, it creates a new app in your workspace with everything pre-configured. **Templates are great for:** - Getting started quickly with a proven use case - Learning best practices for specific agent types - Launching a working agent in minutes instead of hours ## What are Skills? Skills are **composable prompt chunks**: small pieces of a system prompt that introduce specific behaviors into your AI agent. Unlike templates, skills don't create new apps. Instead, you add them to existing apps to enhance their capabilities. Think of skills like plugins: each one teaches your agent a new behavior. **Examples of skills:** - **Chain of Thought Reasoning**: makes the agent reason step by step - **Socratic Tutor**: guides users to answers through questions - **Anti-Hallucination**: prevents the agent from making things up - **Ultra-Concise Mode**: keeps responses short and direct ### How Skills Work Skills are stored separately from your system prompt and composed at runtime. This means: 1. **You can add and remove skills** without editing your system prompt 2. **Skills stack**: add as many as you want, they all apply 3. **Skills are visible** in the expanded system prompt editor under the "Active Skills" section 4. **The agent sees the skill instructions** alongside your system prompt during every conversation ### Personalities Personalities are a special category of skills that define *how* your AI communicates: its voice, tone, and character. Examples include "Patient Mentor", "Corporate Strategist", and "Sardonic Realist". Pick one personality as a foundation, then stack behavioral skills on top. ## Quality Scores Some templates include a **Quality Score**: an automated evaluation showing how well the template performs across test scenarios. The score is generated by running the agent through realistic test cases and having an AI judge evaluate the responses for accuracy and relevance. A score of 90%+ means the template consistently produces high-quality responses for its intended use case. --- # Pricing & Usage Understanding Chipp's usage-based pricing and how to optimize your AI costs --- Understanding how AI pricing works helps you build better apps and control costs. This guide explains our pricing philosophy and gives you tools to estimate and optimize your usage. ## Why Usage-Based Pricing? We get asked about pricing a lot, so let's be upfront about why we charge the way we do. **We want to give every builder access to the best AI models available.** Not watered-down versions, not artificially limited options - the actual best models from OpenAI, Anthropic, and Google. The challenge is that these models have real costs. Running GPT-5 costs more than running GPT-5 Nano. Claude Opus 4 costs more than Claude 3.5 Haiku. If we charged a flat rate, we'd have to either: 1. **Restrict access to premium models** - forcing everyone onto cheaper models 2. **Charge everyone the premium price** - making it unaffordable for many builders 3. **Lose money** - which means we can't stay in business and keep building tools for you Usage-based pricing solves this. It means: - **Budget-conscious builders** can use fast, cost-efficient models like Gemini 2.5 Flash or GPT-5 Nano and keep costs minimal - **Quality-focused builders** can access the most powerful reasoning models like o3 or Claude Opus 4 when they need them - **Smart builders** can mix and match: use affordable models for simple tasks, premium models for complex ones This isn't about being greedy. It's about building a sustainable business that can keep providing best-in-class AI tools to every type of builder, at every budget level. ## How Pricing Works ### Your Plan Includes Usage Builder, Studio, and Studio Pro include a monthly usage allowance: | Plan | Monthly Price | Included Usage | |------|---------------|----------------| | Builder | \$29/mo | \$10 | | Studio | \$99/mo | \$30 | | Studio Pro | \$299/mo | \$100 | If you stay within your allowance, you pay nothing extra. If you need more, you can purchase additional credits in advance. ### Build For You and Fractional CTO Build For You (\$2,500/mo) and Fractional CTO (starts at \$12,500/mo) add a dedicated model capacity lane, and let you bring your own Google, OpenAI, and Anthropic keys with no platform fee on that usage. These plans do not include a usage allowance: usage bills at standard rates, or directly by the provider on your own keys. See [Model Keys and Dedicated Capacity](/docs/guides/model-keys-and-capacity). ### What Counts as Usage? Usage is measured in **tokens**, the units AI models use to process text. Roughly: - 1 token ≈ 4 characters or ¾ of a word - A typical message might use 500-1000 tokens total (input + output) Different models have different costs per token. Premium models cost more, efficient models cost less. Want to understand exactly how tokens work? Check out our [Understanding Tokens](/docs/guides/understanding-tokens) guide with an interactive tokenizer. ## Estimate Your Costs Use this calculator to estimate your monthly AI costs based on expected usage: ## Model Pricing Comparison Here's how different models compare on price. Choose based on your needs: ### Most Cost-Effective Models These models offer excellent quality at the lowest prices: ### Premium Models When you need the best quality, these models deliver: ## Strategies to Optimize Costs ### 1. Match Model to Task Don't use a premium model for simple tasks. Consider: | Task Type | Recommended Approach | |-----------|---------------------| | Quick Q&A, FAQs | Gemini 2.5 Flash or GPT-5 Nano | | General conversation | GPT-5 Mini or Claude 3.5 Haiku | | Content creation | GPT-5 or Claude Sonnet 4 | | Complex analysis | o3 or Claude Opus 4 | | Processing long documents | Gemini 2.5 Pro (best value for 1M context) | ### 2. Optimize Your Prompts Shorter, clearer prompts use fewer tokens: - **Be specific** about what you want - **Remove unnecessary context** from system prompts - **Use concise instructions** instead of verbose explanations ### 3. Consider Response Length If your app doesn't need long responses, instruct the model to be concise. Output tokens typically cost more than input tokens. ### 4. Use the Right Context Window Models with larger context windows (like Gemini 2.5 Pro with 1M tokens) are great for processing long documents. But if you're just doing quick Q&A, you don't need to pay for that capacity. ## Real-World Examples ### Example 1: Customer Support Bot **Use case:** Answering common questions, routing complex issues **Recommended:** Gemini 2.5 Flash ($0.25/M avg) **Monthly cost for 10,000 messages:** ~$2.50 ### Example 2: Content Writing Assistant **Use case:** Helping users write blog posts, emails, marketing copy **Recommended:** GPT-5 ($16/M avg) **Monthly cost for 5,000 messages:** ~$40 ### Example 3: Legal Document Analyzer **Use case:** Reviewing contracts, extracting key terms, summarizing agreements **Recommended:** Gemini 2.5 Pro ($4/M avg, 1M context) **Monthly cost for 1,000 documents:** ~$20 ### Example 4: Research Assistant **Use case:** Deep analysis, multi-step reasoning, complex problem-solving **Recommended:** o3 ($33/M avg) **Monthly cost for 2,000 queries:** ~$33 ## Monitoring Your Usage You can track your usage in real-time: 1. Go to **Settings** → **Billing** in your Chipp dashboard 2. Open **Credits** to see your current balance, or **Usage** to see your usage history by app and model 3. Purchase additional credits from **Credits** when needed We'll automatically notify you when your credits are running low, so you have time to top up before your app pauses. ## FAQ ### What happens if I run out of credits? Your app's AI functionality will pause until you purchase more credits. We'll send you notifications as your balance gets low so you're never caught off guard. You can top up anytime from your billing settings. ### How do I add more credits? Go to **Settings** → **Billing** → **Credits** and purchase credits in advance. Credits are prepaid: there are no surprise bills or overages. You control exactly how much you spend. ### Do unused credits roll over? Yes. Your monthly allowance adds on top of any remaining balance instead of resetting it, and credits never expire. ### Why do output tokens cost more than input tokens? This reflects how AI providers price their APIs. Generating new text (output) requires more computation than processing existing text (input). ### Can I change models mid-conversation? Your app uses one model at a time, but you can change it anytime in the Build settings. The change applies to new conversations. ## What Usage Covers Usage billing covers more than chat interactions and tool calls. These features draw from the same credit balance: ### Voice Interactions Real-time voice conversations with AI are expensive to run. Because voice is part of usage billing, it is available to everyone, not just select customers. You pay for what you use, making voice accessible regardless of your plan. ### Knowledge Source Embeddings Embedding costs for knowledge sources are part of usage billing, so you can add large numbers of documents to power your app's knowledge base and pay only for what you process. ### Image & Video Generation AI-generated images and videos are resource-intensive. Usage billing lets us offer these creative tools to everyone. Generate marketing visuals, product demos, or custom content - paying only for what you create. ### Usage Details Your **Settings** → **Billing** → **Usage** page breaks down your AI usage across apps and models, so you can see exactly what you're paying for and track costs over time. We're building toward a future where every AI capability is available to every builder, with transparent, pay-for-what-you-use pricing. ## Need Help Choosing? If you're not sure which model fits your use case, check out our [Choosing a Model](/docs/guides/choosing-a-model) guide for detailed recommendations based on different scenarios. ## Using with MCP You can access billing and usage information programmatically using the Chipp MCP Server. ### Available Tools | Tool | Description | |------|-------------| | `get_credits` | View current credit balance | | `get_subscription` | Get subscription tier and details | | `get_usage` | Get detailed usage breakdown | ### Example Prompts ``` "How many credits do I have left?" "What's my current subscription plan?" "Show me my usage breakdown for this month" ``` ### Workflow: Usage Monitoring ``` You: Show me my current billing status AI: [Calls get_credits, get_subscription] Subscription: Studio ($99/mo) Credit Balance: $18.50 remaining Monthly Allowance: $30 included Usage this month: - GPT-5: $8.20 (410K tokens) - Claude Sonnet 4: $2.30 (115K tokens) - Gemini Flash: $1.00 (4M tokens) ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- # Model Keys and Dedicated Capacity How Build For You and Fractional CTO organizations get a dedicated model capacity lane and can bring their own Google, OpenAI, and Anthropic keys with no platform fee. --- On the **Build For You** and **Fractional CTO** plans, your agents get two model benefits: - **A dedicated model capacity lane.** Your traffic runs on capacity that is separate from the shared pool, so a busy day for other customers does not slow you down. - **Bring your own keys, with no platform fee.** Connect your own Google, OpenAI, and Anthropic keys. Your agents run on your own quota and your own provider agreements, and the provider bills you directly. Builder, Studio, and Studio Pro run on Chipp's shared capacity and cannot connect their own model keys. ## Dedicated capacity lane Every model provider limits how many tokens one account can send per minute. On the shared pool, a large burst of traffic from any customer counts against the same limit. On Build For You and Fractional CTO, Gemini models run on a dedicated Google Vertex AI lane, separate from the shared pool. There is nothing to set up: the lane turns on with your plan, and **Settings** → **Model Keys** shows it as active. ## Bring your own keys ### Which keys you can connect | Provider | Key type | Where to get it | |----------|----------|-----------------| | Google | Google AI Studio API key | Google AI Studio | | OpenAI | OpenAI API key | OpenAI platform dashboard | | Anthropic | Anthropic API key | Anthropic Console | ### Connect a key 1. Go to **Settings** → **Model Keys**. Only organization owners and admins can add, rotate, or remove keys. Other members see a read-only view. 2. Paste the key for a provider and save. Chipp checks the key with one quick call to the provider before it stores it. If the check fails, nothing is saved. 3. Choose what happens if the key fails (see below). After you save a key, Chipp never shows it again. The page shows only the last four characters, the key status, and when Chipp last checked it. Keys are encrypted at rest. To change a key, rotate it. To stop using it, disconnect it. ### What runs on your key When you connect a key for a provider, your agents' chat responses on that provider's models run on your key. Background work still runs on Chipp's own keys and bills as usual. Examples: conversation titles, memory, knowledge source embeddings, tools, and image generation. ### What it costs Chipp adds **no platform fee** on model usage that runs on your own key. Your provider bills you for those tokens at your own rates. Chipp does not deduct them from your credits. Usage that runs on Chipp's capacity, including the background work above, bills at standard rates. ### If your key fails For each key you choose a fallback: - **Use Chipp's capacity (default).** If your key is rejected, rate limited, or the provider has an error before the response starts, Chipp retries the turn once on its own capacity, on your dedicated lane. That turn bills at standard rates. - **No fallback.** The response fails instead of retrying on Chipp's capacity. If the provider rejects the key itself (for example, it was revoked), Chipp marks the key as invalid and shows the error on the Model Keys page. Connect a new key to fix it. ## Related - [Pricing & Usage](/docs/guides/pricing-and-usage) - [Choosing a Model](/docs/guides/choosing-a-model) --- # Understanding Tokens Learn exactly what tokens are, how they're counted, and why they matter for AI pricing --- If you've used AI tools, you've probably heard about "tokens." But what exactly are they? This guide explains tokens in depth, with interactive tools to help you understand how your text gets tokenized. ## Try It Yourself Use this tool to see exactly how your text gets broken into tokens: ## What Is a Token? A token is the basic unit that AI models use to process text. When you send a message to an AI, it doesn't read characters or words: it reads tokens. Think of tokens as the "vocabulary" the AI uses. Just like how humans break down sentences into words, AI models break down text into tokens. But tokens don't always match our intuition about words. ### Tokens Are Not Words Here's where it gets interesting: | Text | Tokens | Count | |------|--------|-------| | "hello" | `hello` | 1 | | "Hello" | `Hello` | 1 | | "HELLO" | `HE`, `LLO` | 2 | | "tokenization" | `token`, `ization` | 2 | | "ChatGPT" | `Chat`, `G`, `PT` | 3 | Notice how: - Common words are often 1 token - Capitalization can change tokenization - Long or uncommon words get split into pieces - Technical terms may become multiple tokens ### The 4-Character Rule (and Why It's Wrong) You'll often hear "1 token ≈ 4 characters" as a quick estimate. This is a useful approximation, but it's not accurate: | Text | Characters | Actual Tokens | 4-Char Estimate | |------|------------|---------------|-----------------| | "The quick brown fox" | 19 | 4 | 5 | | "supercalifragilisticexpialidocious" | 34 | 9 | 9 | | "🎉🎊🎁" | 3 | 6 | 1 | | "日本語" | 3 | 3 | 1 | | `console.log("hello")` | 21 | 7 | 5 | The approximation works reasonably well for plain English text, but breaks down with: - **Emojis**: Each emoji can be 2-3 tokens - **Non-English languages**: Often more tokens per character - **Code**: Varies widely based on syntax and naming - **Numbers**: Can be tokenized digit-by-digit ## Input vs Output Tokens When you interact with AI, there are two types of tokens: ### Input Tokens (Prompt Tokens) Everything you send to the AI: - Your message - System instructions (set by the app builder) - Conversation history - Any context or documents ### Output Tokens (Completion Tokens) Everything the AI generates: - The response text - Any formatted content (markdown, code, etc.) **Why This Matters for Pricing** Output tokens typically cost 2-4x more than input tokens. Why? 1. **Input**: The model reads your tokens (relatively fast) 2. **Output**: The model generates tokens one-by-one (computationally intensive) This is why shorter, more concise AI responses cost less than long, verbose ones. ## How Tokenization Works AI models use a technique called **Byte Pair Encoding (BPE)** to create their vocabulary. Here's a simplified explanation: 1. **Start with characters**: Begin with individual characters as the base vocabulary 2. **Find common pairs**: Look for character pairs that appear frequently together 3. **Merge pairs**: Combine the most common pairs into single tokens 4. **Repeat**: Continue merging until you have a vocabulary of ~100,000 tokens The result is a vocabulary where: - Very common words ("the", "is", "and") are single tokens - Common word parts ("-ing", "-tion", "un-") are single tokens - Rare words get split into known pieces ### Different Models, Different Tokenizers Not all AI models tokenize text the same way: | Model Family | Tokenizer | Vocabulary Size | |--------------|-----------|-----------------| | GPT-4.1, GPT-5.x | o200k_base | ~200,000 | | Claude 4.x | Claude tokenizer | ~100,000 | | Gemini 3.x | SentencePiece | ~256,000 | This means the same text may have different token counts across models, though the differences are usually small for English text. ## Practical Tips for Managing Tokens ### 1. Be Concise in Your Instructions Shorter system prompts = fewer input tokens on every message. **Verbose (45 tokens):** > "I would like you to act as a helpful assistant that can answer questions about various topics. Please provide detailed and informative responses to any questions that users might ask you." **Concise (15 tokens):** > "You're a helpful assistant. Provide detailed, informative answers." ### 2. Consider Response Length If you don't need long responses, tell the AI: - "Answer in 2-3 sentences" - "Be brief" - "Summarize in one paragraph" ### 3. Watch Conversation Length Every message in your conversation history counts as input tokens. Longer conversations = more tokens. ### 4. Code and Technical Content Code often tokenizes efficiently because: - Common keywords (`function`, `return`, `if`) are single tokens - But variable names and strings add up quickly ## Token Limits (Context Windows) Every AI model has a maximum number of tokens it can process at once (the **context window**). Models also have a **max output** limit on how many tokens they can generate in a single response. | Model | Context Window | Max Output | |-------|---------------|------------| | GPT-5.4 | 128,000 tokens (enforced) | 32,768 tokens | | GPT-4.1 | 1,000,000 tokens | 32,768 tokens | | GPT-4.1 Nano | 1,000,000 tokens | 32,768 tokens | | Claude Opus 4.6 | 1,000,000 tokens | 128,000 tokens | | Claude Sonnet 4.6 | 1,000,000 tokens | 64,000 tokens | | Claude Haiku 4.5 | 200,000 tokens | 64,000 tokens | | Gemini 3.1 Pro (preview) | 1,000,000 tokens | 65,536 tokens | | Gemini 3.5 Flash | 1,000,000 tokens | 65,536 tokens | | o3 | 200,000 tokens | 65,536 tokens | | o4-mini | 200,000 tokens | 65,536 tokens | The context window must fit: - System prompt - Conversation history - Your current message - Space for the response If you exceed the limit, older messages get truncated from the conversation. ## Model Pricing Comparison Prices are per 1 million tokens (including Chipp platform markup): | Model | Input \$/M | Output \$/M | Best For | |-------|----------|-----------|----------| | GPT-5.4 | \$3.25 | \$19.50 | General purpose, latest capabilities | | GPT-4.1 | \$2.60 | \$10.40 | Long context, reliable coding | | GPT-4.1 Nano | \$0.13 | \$0.52 | Ultra-cheap, simple tasks | | Claude Opus 4.6 | \$6.50 | \$32.50 | Deep reasoning, complex tasks | | Claude Sonnet 4.6 | \$3.90 | \$19.50 | Writing, analysis, balanced | | Claude Haiku 4.5 | \$1.30 | \$6.50 | Fast, affordable | | Gemini 3.1 Pro (preview) | \$2.60 | \$15.60 | Long context, multimodal | | Gemini 3.5 Flash | \$1.95 | \$11.70 | Fast, multimodal | | o3 | \$2.60 | \$10.40 | Advanced reasoning | | o4-mini | \$1.43 | \$5.72 | Reasoning on a budget | ## Cost Examples Let's look at real token costs using GPT-5.4 (\$3.25/M input, \$19.50/M output): ### Example 1: Quick Q&A - Your question: 50 tokens ($0.000163) - AI response: 100 tokens ($0.00195) - **Total: $0.002** (less than 1 cent) ### Example 2: Long Document Analysis - Document + question: 5,000 tokens ($0.01625) - Detailed response: 1,000 tokens ($0.0195) - **Total: $0.04** (4 cents) ### Example 3: Extended Conversation - 20 back-and-forth messages - Average input per turn: 2,000 tokens (includes history) - Average output: 300 tokens - **Total: ~$0.25** (25 cents) ### Budget-Friendly Alternative (GPT-4.1 Nano) The same Extended Conversation example with GPT-4.1 Nano (\$0.13/M input, \$0.52/M output): - **Total: ~$0.008** (less than 1 cent) --- # How to Maximize Chipp Capabilities Get the most out of your published Chipp chat agent by mastering key features and best practices. Chat agents are one output type the Alchemist platform supports; for the autonomous software-development system itself, see the Alchemist Platform docs. --- Get the most out of your Chipp AI by mastering the features that matter most. ## How to Use Knowledge to Optimize Your Chipps Your Chipp is only as good as the knowledge behind it. Understanding how AI processes different types of knowledge is the foundation for building effective chatbots. There are three types of knowledge your Chipp can use: 1. **Base Model Knowledge** - What the AI already knows from its training data 2. **Knowledge Sources** - Documents, files, and URLs you upload to your Chipp 3. **Prompt Instructions** - Direct guidance you write in your system prompt Each serves a different purpose. Master all three and your Chipp becomes dramatically more useful. ### The Three Types of Knowledge The AI's base knowledge is broad but generic. It knows about the world, but it doesn't know about *your* business, *your* products, or *your* specific use case. That's where knowledge sources come in. ### Why Upload Knowledge on Top of AI's Existing Knowledge Uploading your own knowledge sources gives your Chipp: - **Accuracy** - Answers grounded in your actual content, not AI assumptions - **Specificity** - Details about your products, services, and processes - **Currency** - Up-to-date information the base model doesn't have - **Authority** - Responses that reflect your brand voice and expertise The AI's training data has a cutoff date. Your knowledge sources don't. Upload your latest documentation and your Chipp stays current. ### Knowledge Source vs. Prompt: The Technical Difference **Knowledge Sources** are retrieved dynamically. When a user asks a question, Chipp searches your uploaded documents and pulls relevant chunks into context. This is called RAG (Retrieval-Augmented Generation). **Prompts** are always present. Your system prompt is included in every single conversation, regardless of what the user asks. | Feature | Knowledge Sources | Prompts | |---------|------------------|---------| | **When used** | Retrieved when relevant | Always included | | **Best for** | Large amounts of reference content | Personality, rules, behavior | | **Size limit** | Large (many documents) | Small (few thousand words) | | **Updates** | Upload new files anytime | Edit in **Brain** > **Prompt** | **Rule of thumb**: Put facts and reference material in knowledge sources. Put personality, tone, and behavioral rules in your prompt. --- ## How to Update Knowledge Sources Automatically How to automate refetching of knowledge sources. Watch the tutorial below to learn when and how to automate refetching for your knowledge sources. --- ## Difference between Knowledge Source vs. Prompt Watch the tutorial below to learn when and how to use knowledge sources vs. system prompts to optimize output. See the section above on [Knowledge Source vs. Prompt: The Technical Difference](#knowledge-source-vs-prompt-the-technical-difference) for a detailed breakdown. --- ## How to Use Markdown to Optimize Your Chipps Below you can find a quick introduction to how and why to use Markdown to optimize your Chipps. Mastering the basics of Markdown for both instructions and knowledge sources can make a massive difference in the accuracy and ease of editing of your AI tools. Watch the tutorial below to learn how to make sure your AI understands exactly what you're trying to say by using Markdown. ### What is Markdown? Markdown is a simple way to add formatting (like bold, italics, lists, and headings) to plain text. It's widely used in online writing, documentation, and AI tools to make instructions clearer and more organized. ### Why Use Markdown in AI Instructions? - **Clarity:** Well-formatted instructions are easier for both users and AI assistants to understand. - **Emphasis:** You can highlight important words or steps, making sure nothing gets missed. - **Organization:** Headings and lists help break information into manageable sections. ### Basic Markdown Formatting Here are some easy ways to use Markdown: **Headings:** Use #'s to help your AI know which sections belong where in hierarchy. E.g. Heading 2 (##) belongs under Heading 1 (#), and Headings 3 (###) belong under both Headings 1 & 2. ``` # Main Section Title ## Section Title ### Subsection #### Sub-subsection ``` **Bold and Italic:** - **Bold** for important words - *Italic* for emphasis **Lists:** - Step 1 - Step 2 - Step 3 **Links:** If you'd like to learn more, or have access to more examples on markdown and using HTML in your Chipps, you can find a great list here: [Markdown Guide](https://www.markdownguide.org/basic-syntax) ### How to Use Markdown in Your AI Instructions When you write instructions for your AI assistant, use Markdown to: - Make step-by-step guides with clear sections and hierarchy. - Highlight key actions or warnings in bold. - Organize long instructions with headings. **Example - Plain instruction:** Please collect user feedback and send a thank you message. **Example - With Markdown:** ``` ## Collect Feedback - Ask the user for their feedback. - **Thank the user** for their input. - Save the feedback for future improvements. ``` Using Markdown helps your AI assistant communicate more clearly and professionally, no coding required! --- ## How to Share Images & Gifs in Your Chipp Below you can find a quick introduction to how you can share images and gifs as a part of your Chipp user flow. Watch the tutorial below to learn how to use images and gifs to liven up your Chipp chats. *Video coming soon* --- ## How to Optimize Video on Chipp *Content coming soon* --- ## How to Use Video for Research & Feedback (YouTube, TikTok, Instagram) *Content coming soon* --- ## How to Create Image Variations for Social Platforms In this lesson you'll learn how to use the image generation tool to create variations of the same image to fit different platforms or purposes. Watch the tutorial below to learn how to create image variations for Facebook, Instagram, and other ad platforms. --- ## How to Train a Personalized Curriculum Creator In this lesson you'll learn how to create a structure for anyone to upload information, and get a personalized lesson plan as the output. Watch the tutorial below to learn how to help students create fully personalized lesson plans or growth paths. --- ## How to Create Videos with Chipp Learn how you can create videos on Chipp. Video generation uses the **Generate Video** tool, powered by Google Veo 3. --- ============================================================ SECTION: Agent Capabilities ============================================================ # Image Recognition How to get the best results when analyzing images with your Chipp app --- Your Chipp app can analyze images uploaded by users. This guide explains how image recognition works and how to get the best results. ## How It Works When a user uploads an image, Chipp processes it in one of two ways depending on your app's model: ### Vision-Capable Models (Recommended) Models with native vision capabilities see images directly, just like a human would. The image is embedded in the conversation and the model can reference it naturally. **Vision-capable models:** | Provider | Models | |----------|--------| | OpenAI | GPT-5 family (GPT-5.x, GPT-5 Mini, GPT-5 Nano), GPT-4.1, GPT-4.1 Mini, GPT-4.1 Nano, GPT-4o | | Anthropic | All Claude models (Claude Sonnet 5.5, Claude Opus 5.5, Claude Haiku 5.5, Claude Sonnet 4.x, Claude Opus 4.x, Claude Haiku 4.5, Claude 3.x) | | Google | Gemini 3.x, Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.5 Flash Lite | **Models WITHOUT vision:** - OpenAI o-series (o1, o1 Pro, o3, o3 Pro, o3-mini, o4 Mini) ### Non-Vision Models (Fallback) Models without native vision (like the o-series reasoning models) cannot see uploaded images. Chipp does not pass the image to these models, so the model only sees your user's text. Through the API, a request that attaches an image to a non-vision model is rejected with an `IMAGE_INPUT_UNSUPPORTED_BY_MODEL` error. If your app needs to understand images, choose a vision-capable model. ## Getting the Best Results ### 1. Choose the Right Model For apps that heavily rely on image analysis, select a vision-capable model: 1. Go to your app in the Chipp dashboard 2. Go to **Brain** > **Prompt** and find the **Intelligence** card 3. Under **Chat Model**, select a vision-capable model like GPT-5 or Claude Sonnet 5.5 ### 2. Enable Image Upload Make sure users can upload images: 1. Go to **Brain** > **Capabilities** and expand the **Customize** card 2. Find **Image Upload** ("Allow users to upload images for the model to see") 3. Toggle it **ON** ### 3. Image Quality Tips For best recognition accuracy: - **Resolution**: Higher resolution images produce better results - **Lighting**: Well-lit images are easier to analyze - **Focus**: Ensure the subject is in focus and not blurry - **Format**: JPEG, PNG, GIF, and WebP are all supported ### 4. Prompting for Analysis Guide users to be specific about what they want analyzed: **Good prompts:** - "What math equations are shown in this image?" - "Identify all the plants in this photo" - "What text appears on this sign?" **Vague prompts:** - "What is this?" - "Tell me about the image" ## Comparing to ChatGPT If you notice differences between your Chipp app and ChatGPT's native image analysis, consider: 1. **Model selection**: ChatGPT uses GPT-5 by default. Ensure your Chipp app also uses GPT-5 or a comparable vision model like Claude Sonnet 5.5. 2. **System prompt**: Your app's personality and instructions may influence how it interprets images. ChatGPT has different default behaviors. 3. **Context window**: ChatGPT maintains conversation context differently. For complex multi-image analysis, results may vary. ## Troubleshooting ### Images Not Being Analyzed - Verify **Image Upload** is enabled in your app's **Customize** card - Verify your app uses a vision-capable model - Check that the user is uploading supported formats (JPEG, PNG, WebP, GIF) - Ensure images are from supported sources (direct uploads, not all external URLs) ### Poor Accuracy - Switch to a vision-capable model (GPT-5, Claude Sonnet 5.5, etc.) - Ask users to provide clearer, higher-resolution images - Add specific instructions in your system prompt about how to analyze images ### Slow Response Times Image analysis typically takes 5-15 seconds depending on image complexity. For faster responses: - Use smaller image files when possible - Consider GPT-5 Nano or Claude Haiku 4.5 for speed vs. accuracy tradeoff ## Model Comparison for Vision | Model | Vision Quality | Speed | Best For | |-------|---------------|-------|----------| | GPT-5 | Excellent | Medium | Complex reasoning about images | | Claude Sonnet 4.5 | Excellent | Fast | Detailed visual descriptions | | Gemini 2.5 Pro | Excellent | Medium | Multi-image comparisons, long context | | GPT-5 Mini | Very Good | Fast | Balanced performance | | GPT-5 Nano | Good | Very Fast | Quick, simple analysis | | Claude Haiku 4.5 | Good | Very Fast | Fast responses | | Gemini 2.5 Flash | Very Good | Fast | Balanced speed and quality | --- # Image Generation Generate and edit images directly inside your chatbot using multiple AI image models. --- Chipp apps can generate and edit images directly in the chat conversation. Your consumers simply describe what they want, and the AI creates it -- no separate tools or plugins required. ## Available Models Chipp supports six image generation models from five providers. Each model has different strengths, costs, and capabilities. | Model | Provider | Best For | Cost per Image | Max Resolution | |-------|----------|----------|----------------|----------------| | **Gemini 3 Pro** | Google | Highest quality, text rendering, multi-reference editing | ~$0.17 | 4K | | **GPT Image 1.5** | OpenAI | Precise instruction-following edits | ~$0.04 | 4096x4096 | | **FLUX.1 Kontext Pro** | Black Forest Labs | Conversational editing, preserving originals | ~$0.05 | 1024x1024 | | **Stability AI SD 3.5** | Stability AI | Inpainting, search-and-replace, background removal | ~$0.05 | 1024x1024 | | **Gemini 2.5 Flash** | Google | Fast, affordable, high-volume generation | ~$0.05 | Dynamic | | **Grok Imagine Image 2.0** | xAI | Dense layouts, small-text rendering, low cost | ~$0.05 | 2K | > **Note:** GPT Image 1.5 is the default model for new apps. Gemini 3 Pro is the recommended premium option for apps that need the highest quality output. ### Model Capabilities Not every model supports every operation: - **Generation** -- Create images from text descriptions. All models support this. - **Editing** -- Modify an existing image based on instructions. Supported by all six models. - **Inpainting** -- Fill in or replace specific regions of an image. Supported by Gemini 3 Pro and Stability AI. - **Blending** -- Combine multiple reference images into a new composition. Supported by Gemini 3 Pro, Gemini 2.5 Flash, and Grok Imagine Image 2.0 (up to 3 source images). ## Enabling Image Generation Image generation is enabled by default for all apps on all tiers. To choose a model or adjust settings: **Open Capabilities.** Navigate to your app in the builder and go to **Brain** > **Capabilities**. **Find the Image Model Section.** Scroll down to the **Image Model** card. You will see a grid of available models. **Select a Model.** Click on the model you want to use. The selected model will be highlighted with your brand color. **Adjust Model Settings.** Each model exposes different configuration options. Adjust them below the model grid after selecting a model. **Changes save automatically.** The builder saves your selection automatically. The new model will be used for all future image generation requests. ## Model Settings Each model offers different configuration parameters that your consumers do not see -- these are builder-level defaults applied to every generation. ### GPT Image 1.5 (OpenAI) - **Quality** -- Low (fastest, cheapest), Medium (balanced, default), or High (best quality). Higher quality costs more tokens. - **Size** -- 1024x1024 (square), 1536x1024 (landscape), or 1024x1536 (portrait). - **Background** -- Auto (model decides), Transparent (PNG only, useful for logos and stickers), or Opaque (solid background). ### Gemini 3 Pro - **Aspect Ratio** -- Choose from 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, or 2:3. The model adapts the composition to fit the chosen ratio. ### FLUX.1 Kontext Pro - **Aspect Ratio** -- Same options as Gemini 3 Pro. - **Prompt Upsampling** -- When enabled, the model automatically enhances your consumer's prompt for better results. ### Stability AI SD 3.5 - **Aspect Ratio** -- 1:1, 16:9, 9:16, 4:5, 5:4, 3:2, or 2:3. Only applies to new generations; edits preserve the original dimensions. - **Negative Prompt** -- Describe elements to exclude (e.g., "blurry, low quality, watermark"). Guides the model away from unwanted content. - **Edit Strength** -- Slider from 0.1 to 1.0. Lower values make subtle tweaks; higher values allow dramatic transformations. Default is 0.7. ### Grok Imagine Image 2.0 (xAI) - **Aspect Ratio** -- Same options as Gemini 3 Pro. - **Resolution** -- 1K (cheaper, default) or 2K (higher detail). - **Quality** -- Low (cheapest, default) or Medium. ## How It Works for Consumers Consumers interact with image generation through natural language. They do not need to know which model is configured -- they just ask. ### Generating New Images Consumers describe what they want, and the AI calls the `generateImage` tool automatically: - "Create a logo for my coffee shop called Bean There" - "Generate a watercolor painting of a sunset over mountains" - "Make me a product mockup of a blue water bottle" The generated image appears inline in the chat conversation. ### Editing Existing Images Consumers can upload an image and ask for changes. The AI uses the uploaded image as a reference: - "Make the sky more orange" (after uploading a landscape photo) - "Remove the background" (after uploading a product photo) - "Add a hat to the person in this photo" There is also a dedicated `editImage` tool that automatically resolves the most recently uploaded image, so consumers can simply say "change the color to blue" without re-uploading. ### Multi-Image Blending With Gemini models, consumers can upload multiple reference images and ask the AI to combine them: - "Blend these two photos into a single composition" - "Use this character from image 1 in the scene from image 2" > **Tip:** Gemini 3 Pro supports up to 14 reference images in a single request, making it the best choice for complex multi-image workflows. ## Disabling Image Generation If your app does not need image generation, you can disable it under **Brain** > **Capabilities**: in the **Tools & Actions** card, turn off the **Generate Image** switch. When disabled, the `generateImage` and `editImage` tools are removed from the agent's toolset entirely -- consumers will not be able to request images. ## Billing Image generation is billed per image against your organization's credit balance. The cost per image depends on the model you select (see the table above). Costs shown in the builder include a 30% platform markup over the raw provider cost. --- # Video Generation Generate short videos from text descriptions using Google Veo 3 directly inside your chatbot. --- Chipp apps can generate short videos from text descriptions using Google Veo 3. Consumers describe what they want, and the AI produces a video with audio -- delivered as a playable download card directly in the chat. > **Note:** Video generation is available on all tiers. It draws on your organization's Chipp credit balance. ## How It Works Video generation is an asynchronous process. Unlike text or image responses that appear immediately, videos take 1-4 minutes to produce. The chat UI keeps the consumer informed throughout. **Consumer Asks for a Video.** The consumer describes the video they want in natural language. The AI crafts a detailed prompt (100-150 words) covering subject, action, camera movement, lighting, mood, style, environment, and color palette. **Job Created.** The AI calls the `generateVideo` tool, which creates a background job and returns a progress indicator inline in the chat. **Progress Updates.** As the video moves through the pipeline (queued, generating, uploading), real-time WebSocket events update the progress indicator in the chat. Consumers see the current phase and an estimated time remaining. **Video Ready.** When the video is complete, a download card replaces the progress indicator. The consumer can play the video directly or download it. ## Video Parameters The AI controls these parameters based on the consumer's request: | Parameter | Options | Default | Description | |-----------|---------|---------|-------------| | **Duration** | 4s, 6s, 8s | 8s | Length of the generated video | | **Aspect Ratio** | 16:9, 9:16 | 16:9 | Landscape or portrait orientation | | **Negative Prompt** | Free text | None | Things to avoid in the output | | **Reference Image** | URL | None | An optional starting image to animate (image-to-video) | All videos are generated at **1080p resolution** with **audio included**. > **Tip:** When a consumer provides a reference image, Veo uses it as the starting frame and animates it (image-to-video). Only PNG and JPEG images are supported; other formats are skipped and the video is generated from the text prompt alone. ## The Generation Pipeline Behind the scenes, video generation follows a multi-phase pipeline: 1. **Pending** -- Job created in the database 2. **Queued** -- Submitted to the Google Veo 3 API via Vertex AI 3. **Generating** -- Veo is rendering the video (this is the longest phase, typically 2-4 minutes) 4. **Uploading** -- Finished video is uploaded to secure cloud storage 5. **Completed** -- Video URL is saved and delivered to the consumer If any phase fails, the job is marked as failed and the consumer receives an error message. Failed jobs can be retried. ## Example Use Cases Video generation works well for: - **Product demos** -- "Create a 6-second video showing a phone rotating on a white background" - **Social media content** -- "Generate a portrait video of coffee being poured in slow motion with warm lighting" - **Concept visualization** -- "Make a video of a drone flying over a futuristic city at sunset" - **Storyboarding** -- "Show a character walking through a forest with dappled sunlight, camera following from behind" - **Marketing clips** -- "Create a video of ocean waves with text overlay saying 'Find Your Peace'" ### Prompting Tips The AI automatically crafts detailed prompts, but consumers get better results with specificity: - **Good**: "Create a video of a golden retriever running through autumn leaves in a park, slow motion, warm afternoon sunlight, shallow depth of field" - **Less effective**: "Make a video of a dog" Including details about camera movement (tracking shot, dolly zoom, static), lighting (golden hour, neon, dramatic), and mood (cinematic, playful, serene) significantly improves output quality. ## Storage and Delivery Generated videos are stored in Google Cloud Storage under your organization's workspace. Each video gets a unique URL that is served through the standard file download system with signed URLs. Videos persist as long as the associated chat session exists. The video appears in the chat as a rich download card, similar to how file attachments are displayed. Consumers can play the video inline or download the MP4 file. ## Billing Video generation is billed per video as `video_generation` usage against your organization's credit balance. Each video counts as one unit regardless of duration or aspect ratio. > **Warning:** Video generation is more expensive than image generation. The cost reflects the compute required to render 1080p video with audio via Google Veo 3. Monitor your usage in the billing dashboard. ## Limitations - **Maximum duration is 8 seconds.** Veo 3 supports short-form video generation only. - **Generation takes 1-4 minutes.** This is inherent to the Veo pipeline and cannot be accelerated. - **Generation may time out** after 6 minutes if the Veo API is under heavy load. The consumer will see an error and can retry. - **No video editing.** Unlike image generation, consumers cannot upload a video and ask for modifications. Each generation is from scratch (though a reference image can serve as the starting frame). - **YouTube URLs are not supported** as reference images. Consumers must provide direct image URLs or upload files. --- # Deep Research and Deep Thinking Give your chatbot the ability to conduct multi-source research and show visible step-by-step reasoning. --- Chipp apps support two advanced reasoning capabilities that go beyond standard chat responses: **Deep Research** for comprehensive multi-source investigation, and **Deep Thinking** for visible step-by-step reasoning. Both give your consumers more thorough, transparent answers to complex questions. Chipp uses a **two-tier model architecture** for Deep Research: a fast, cost-efficient specialist model extracts and normalizes evidence from web sources, while your app's primary model synthesizes that evidence into a final answer. This separation lets you optimize for both speed and quality without paying for high-end reasoning on every extraction task. > **Warning:** Deep Research and Deep Thinking are available on every plan, including Free. Both are off by default: turn them on in **Brain** > **Capabilities**. ## Two-Tier Deep Research Architecture Deep Research uses two separate models working together: 1. **Specialist Model** (extraction & evidence normalization): Processes raw web sources and transforms them into a structured, citation-preserving evidence packet. This role uses a cost-optimized model that specializes in efficient source extraction. 2. **Main Model** (synthesis): Your app's primary model, which reads the evidence packet and synthesizes a comprehensive, cited answer. This is the same model that powers all other conversations. This two-tier approach gives you the best of both worlds: you pay for economical source processing while reserving your main model for final synthesis and complex reasoning. ### Default Models New apps ship with Chipp's recommended defaults: - **Main/Synthesis Model**: **Claude Sonnet 5.5**, the default model for new apps. It handles synthesis and all other conversations. - **Deep Research Specialist Model**: **DeepSeek V4 Flash**, for fast and cost-efficient evidence extraction. These defaults are optimized for the cost-sensitive research use case. Most builders never need to change them. ### Customizing Models (Advanced) You can override both models in the app builder: - **Main Model**: Choose any supported chat model in **Brain** > **Prompt** (the same selector you use for general chat). This model synthesizes research findings and powers all other conversations. - **Deep Research Specialist Model**: In **Brain** > **Capabilities**, open the **Deep Research** card and pick a **Research specialist model** from the curated list (or leave it on **Default**). This model only runs on the evidence-extraction step and does not affect synthesis quality. Model changes apply immediately to new research requests. ## Deep Research Deep Research spawns multiple parallel research agents that independently search the web, read pages, and compile findings. The results are synthesized into a single, comprehensive report with citations. ### Invocation Policy Turn on **Enable deep research** in **Brain** > **Capabilities** (in the **Deep Research** card), then choose an **Invocation policy**: - **Auto** (default): The AI uses its own judgment. It activates Deep Research for questions that genuinely benefit from multi-source research (market analysis, comparisons, current events) and skips it for simple questions or conversations referencing existing context. - **Required**: The AI must use Deep Research for every research-eligible question. Useful if you want to guarantee comprehensive sourcing for all user queries. - **Off**: Deep Research is disabled, even while the toggle is on. The app still answers questions, but without the parallel research capability. Most apps use **Auto** and never need to adjust this setting. ### When the AI Uses Deep Research By default (Auto mode), the AI decides to use Deep Research for questions that require broad investigation: - Market research and competitive analysis - Technical deep dives requiring multiple authoritative sources - "Compare X vs Y vs Z" questions with multiple dimensions - Industry reports and comprehensive analyses - Multi-faceted questions where a single web search would be insufficient It does **not** use Deep Research for simple factual questions, casual conversation, follow-up questions where context already exists, or questions about the consumer's own data. ### How It Works **Decomposition.** The AI breaks the consumer's question into 2-6 focused sub-questions. Each targets a distinct aspect of the topic. For example, "Compare React vs Vue vs Svelte for enterprise apps" might become sub-questions about performance, ecosystem, hiring, learning curve, and corporate backing. **Round 1: Parallel Investigation.** Each sub-question gets its own research agent that independently searches the web, reads full pages, and follows links to primary sources. These agents run in parallel for speed. **Gap Analysis.** After Round 1, an analysis step reviews all findings for gaps, contradictions, and areas needing deeper investigation. If the research is already comprehensive, it moves straight to synthesis. **Round 2: Follow-Up Research (if needed).** Up to 4 follow-up agents investigate gaps identified in the analysis. These agents have context from Round 1, so they can verify claims, cross-reference sources, and fill in missing information. **Synthesis.** All findings from both rounds are synthesized into a single, well-structured report organized by theme (not by sub-question). Every claim includes inline citations with links to sources. ### Citation Integrity Chipp's two-tier architecture includes built-in citation integrity: 1. The **specialist model** extracts raw findings from web sources and produces a structured evidence packet (claims, excerpts, source URLs, publication dates, relevance scores). 2. The specialist's citations are validated: any claim citing a source that wasn't in the original web search is dropped. 3. The **main model** synthesizes the final answer using ONLY the validated evidence packet. It cannot invent new citations; every claim in the final answer links back to the evidence the specialist extracted. 4. If the specialist produces malformed output, the system falls back to the original web sources, ensuring the answer is always grounded and citable. This means every citation in a Deep Research result is verifiable from the actual sources searched, not inferred or synthesized by the models. ### What the Consumer Sees During Deep Research, the chat UI shows real-time progress: 1. **Plan** -- The sub-questions being investigated 2. **Research progress** -- Which agents are running, how many sources have been found 3. **Gap analysis** -- Whether follow-up research is needed 4. **Final report** -- A comprehensive response with inline source citations A typical Deep Research operation takes 15-45 seconds depending on the complexity of the question and the number of follow-up investigations needed. ### Example Prompts - "Research the current state of AI regulation in the EU, US, and China" - "Compare the top 5 CRM platforms for small businesses under 50 employees" - "What are the latest developments in solid-state battery technology?" - "Analyze the competitive landscape for AI code assistants" ## Deep Thinking Deep Thinking enables visible, structured reasoning before the AI answers. Instead of jumping directly to a response, the AI creates a step-by-step plan and works through it, showing its reasoning process to the consumer. Deep Thinking always uses your app's primary model (the same model that powers all your other conversations). There is no separate specialist model for reasoning: the full depth of your main model is reserved for this task. ### Invocation Policy Turn on **Enable deep thinking** in **Brain** > **Capabilities** (in the **Deep Thinking** card), then choose an **Invocation policy**: - **Auto** (default): The AI uses its own judgment. It activates Deep Thinking for multi-part questions and complex analysis tasks where step-by-step reasoning provides clear value. - **Required**: The AI must use Deep Thinking for every applicable question. Useful if you want to guarantee transparent, structured reasoning for all analyses. - **Off**: Deep Thinking is disabled, even while the toggle is on. The app still answers questions, but without showing step-by-step reasoning. Most apps use **Auto**. ### When the AI Uses Deep Thinking The AI automatically uses Deep Thinking for questions that benefit from structured analysis: - Comparing two or more options, approaches, or strategies - Questions with multiple distinct parts that each need analysis - Providing recommendations based on specific criteria - Complex analysis requiring structured reasoning - Cross-referencing multiple knowledge base sources - Combining web research with knowledge base data It does **not** use Deep Thinking for simple factual questions with a single clear answer, casual conversation, brief follow-ups, or yes/no questions. ### How It Works **Plan Creation.** The AI creates a reasoning plan with 2-8 steps. Each step maps to a specific action: searching knowledge, browsing the web, analyzing data, comparing options, or synthesizing conclusions. **Step Execution.** The AI works through each step in order, using the appropriate tools (knowledge search, web browse, code execution, etc.) as needed. **Comprehensive Response.** After completing all steps, the AI produces a thorough response informed by the structured reasoning process. ### What the Consumer Sees During Deep Thinking, the chat UI shows the reasoning steps as the AI works through them. Each step has a label (e.g., "Searching knowledge base for pricing data", "Comparing feature sets", "Synthesizing recommendation") and updates in real time as the AI progresses. This transparency helps consumers understand how the AI arrived at its answer and builds trust in complex recommendations. ### Example Prompts - "Should I use PostgreSQL or MongoDB for my e-commerce app?" - "Review my business plan and identify the three biggest risks" - "What's the best marketing strategy for a B2B SaaS launch?" - "Analyze our Q3 sales data and recommend focus areas for Q4" ## Deep Research vs. Deep Thinking | | Deep Research | Deep Thinking | |---|---|---| | **Purpose** | Gather and synthesize information from many external sources | Structure reasoning about available information | | **Speed** | 15-45 seconds | 10-30 seconds | | **Sources** | Parallel web search agents → evidence extraction → synthesis | Knowledge base, web, code execution | | **Output** | Cited research report (citations guaranteed verifiable) | Structured analysis with visible reasoning | | **Best for** | "What is the current state of X?" | "What should I do about X?" | | **Models** | Specialist (extraction) + Main (synthesis) | Main model only | | **Agents** | 2-6 parallel sub-agents + follow-up agents | Single agent with multi-step plan | In practice, the AI often combines both: using Deep Research to gather information and Deep Thinking to analyze it. The AI decides which capability to use (or both) based on the nature of the question. ## Plan Requirements Both capabilities are available on every plan, including Free. Their token usage is billed against your organization's credit balance (see below). ## Billing and Cost Optimization Both Deep Research and Deep Thinking consume tokens, billed against your organization's credit balance. ### Deep Research Costs Deep Research runs multiple parallel specialist extraction calls (one per sub-question, plus gap analysis) followed by a final synthesis on your main model. Token usage breaks down across stages: - **Specialist stages** (retrieval, evidence extraction, gap analysis): Run on your Deep Research specialist model (default: DeepSeek V4 Flash), optimized for cost efficiency. - **Synthesis stage**: Runs on your main model (default for new apps: Claude Sonnet 5.5), once, after all extraction is complete. A typical Deep Research operation uses 10-20x more tokens than a standard chat response. However, because the cost-heavy synthesis step runs only once with validated evidence (not once per sub-question), using a budget specialist for extraction dramatically reduces total cost compared to running every stage on a high-end model. If you're doing high-volume research and cost is a concern, the default models are already optimized for that use case. Switching to more expensive models will increase your bill proportionally. ### Deep Thinking Costs Deep Thinking has modest overhead since it uses a single model with structured planning: typically 3-5x a standard response, all on your main model. ### Token Transparency Deep Research records token usage separately for each stage and model (specialist stages on the specialist model, synthesis on the main model), so switching either model changes only the cost of its own stages. ## Verifying When Capabilities Run You can see when Deep Research and Deep Thinking were used in your app's performance dashboard: - **Performance dashboard**: Go to **Insights** > **Performance** and open a session. Each response that used them shows a **Deep Research** or **Deep Thinking** badge. - **Deep Research triggered**: Look at the research progress UI displayed to consumers (plan, research progress, gap analysis). - **Invocation policy**: Check the **Deep Research** and **Deep Thinking** cards in **Brain** > **Capabilities** to see whether each is on, and whether it is set to Auto, Required, or Off. This transparency helps you understand your token consumption and debug whether capabilities are activating as expected. > **Tip:** If your app primarily serves simple Q&A use cases, consumers will rarely trigger these capabilities. The AI only activates them for questions that genuinely benefit from structured reasoning or multi-source research. Set your invocation policy to **Auto** and let the AI decide based on question content. --- # Heartbeat - Proactive AI Outreach Set up your AI to automatically check in with users on a schedule, delivering personalized messages via email, SMS, WhatsApp, Slack, Google Chat, webchat, the Chipp iPhone app, or webhooks. --- Heartbeat turns your AI from reactive to proactive. Instead of waiting for users to start a conversation, your agent periodically checks in with each consumer -- reviewing their context, memories, and your instructions -- and sends a personalized message when something needs attention. ## How It Works ``` On each scheduled run, for each consumer: 1. Your AI reviews the consumer's memories, recent messages, and your instructions 2. It uses all available tools (knowledge search, integrations, web browsing, etc.) 3. If something needs attention → delivers a personalized message 4. If nothing needs attention → stays silent (no spam) ``` The key insight: your AI has access to **all the same tools** as a normal conversation. A heartbeat isn't just a canned message -- it's a full agent evaluation that can search knowledge, check integrations, and gather real-time data before deciding what to say. > **Note:** **Did you know?** Heartbeat agents inherit every Custom HTTP Action you've configured. That means your heartbeat can call your own [Builder API](/docs/builder-api/overview), query external services, or run any tool you've already set up for regular chat. See [Get Your App's Own Usage Stats](/docs/guides/programmatic-usage-stats) for a worked example: a weekly heartbeat that emails you usage stats fetched from your own app's analytics endpoint. ## Getting Started **1.** Open Heartbeat Settings Navigate to your app's **Launch** tab and click **Heartbeat** in the sub-navigation. **2.** Enable Heartbeat Toggle on **Enable heartbeat**. If this is your first time, a setup wizard walks you through choosing a template, delivery channels, and schedule. **3.** Write Your Instructions Tell your AI what to check for. Think of it as a checklist the AI evaluates for each consumer: ``` - Has the user been active in the last 7 days? - Any unresolved questions from their last conversation? - Is there a relevant product update to share? - Are there upcoming deadlines they should know about? ``` Your AI will use its tools to evaluate each item and compose a message only when something is relevant. **4.** Choose Delivery Channels Select one or more channels for delivery. Your AI generates the message once and delivers it to all selected channels simultaneously: | Channel | Best For | |---------|----------| | **Email** | Broadest reach -- works even when users aren't online | | **Webchat** | In-app nudges for users who are currently active | | **WhatsApp** | Personal, high-engagement messages (requires WhatsApp integration) | | **SMS** | Text messages to consumers with a known phone number (requires SMS integration) | | **Slack** | Team and workspace notifications (requires Slack integration) | | **Google Chat** | Posts to a Google Chat space or DM (requires Google Chat connection) | | **iPhone app** | Push notification on the Chipp iPhone app; a tap opens the chat | | **Webhook** | Triggering external workflows via JSON POST | **iMessage** appears in the channel list but is marked coming soon and cannot be selected yet. You can select multiple channels at once. For example, select both **Email** and **Webchat** to reach users wherever they are. If no channels are selected, the system auto-detects from each consumer's last conversation channel. **5.** Set the Schedule Choose how often heartbeats run: - **Interval**: Every N hours (e.g., every 4 hours) - **Daily**: At a specific time each day (e.g., 9:00 AM Eastern) - **Weekly**: On a specific day and time (e.g., Monday at 9:00 AM) ## Curated Email Recipients When email is one of your selected channels, you can choose who receives email heartbeats: - **All consumers** (default): Every eligible consumer with an email address gets the heartbeat - **Curated list**: Only consumers whose emails match your curated list receive email heartbeats This is useful when you want to target specific users for email outreach while still delivering to all users on other channels like webchat. To set up a curated list: 1. Select **Email** as a delivery channel 2. Click **Curated list** in the toggle that appears 3. Add consumer email addresses to the list Other selected channels (webchat, WhatsApp, Slack) still reach all eligible consumers regardless of the curated list. ## Additional Recipients Beyond your existing consumers, you can add **additional email recipients** who receive heartbeat messages even though they haven't chatted with your app. This is great for: - Team members who want to stay informed - Stakeholders who need regular updates - Email lists for broadcast-style outreach Additional recipients get a single shared message (no per-user personalization since they have no conversation history or memories). ## Slack Channel Broadcasts If your app has a Slack integration, you can broadcast heartbeat messages directly to Slack channels. This works independently of per-consumer delivery -- one LLM call generates the message, and it's posted to all configured channels. ## Testing Heartbeats Before going live, test your heartbeat configuration: 1. In the **Test** section, select a consumer (your own account is pinned at the top) 2. Click **Send Test** (for background-task schedules the button reads **Run Test (executes real tools)**) 3. The test runs the full agent loop with real tools and delivers to the resolved channel > **Note:** Test heartbeats bypass scheduling checks (budget, active hours, consecutive OK limits) so you can test anytime. They don't count toward your daily/monthly budget or affect sweep eligibility. ## Quiet Hours & Anti-Spam Heartbeat includes several built-in safeguards: - **Active hours**: Only send during business hours (e.g., 9 AM - 10 PM in your timezone) - **Interaction recency**: Skip consumers who just chatted (default: 60 min cooldown) - **Consecutive OK limit**: Stop checking consumers after N consecutive "nothing to say" evaluations (default: 5) - **Deduplication**: Don't send the same message text within 24 hours - **Daily/monthly budget caps**: Hard limits on total heartbeat runs per app ## How the AI Decides What to Say When the AI evaluates a consumer and has nothing useful to say, it responds with `HEARTBEAT_OK` internally. This is silently suppressed -- the consumer never sees it. This means: - **No spam**: Consumers only hear from your AI when something is genuinely relevant - **Cost efficient**: Silent check-ins use tokens but are much cheaper than full outreach messages - **Natural conversations**: When a consumer replies to a heartbeat message, it starts a full conversation with complete context and tools ## Webhook Delivery When webhook is selected as a delivery channel, heartbeat output is POSTed as JSON to your configured URL: ```json { "event": "heartbeat.message", "applicationId": "...", "applicationName": "My App", "consumerId": "...", "consumer": { "name": "Jane", "email": "jane@example.com", "identifier": "..." }, "text": "The heartbeat output message", "timestamp": "2026-03-19T15:00:00.000Z" } ``` You can optionally set a **webhook secret** that's sent in the `X-Webhook-Secret` header for request verification. ## Pricing & Limits Heartbeat is included on **all paid plans** (Builder and above). Free workspaces get a **free trial of 10 heartbeats** to try it out, then upgrade for unlimited proactive outreach. Each tier has different limits: | Tier | Min Interval | Daily Cap | Consumers/Sweep | |------|-------------|-----------|-----------------| | Free | 60 min | 5 | 5 (10 heartbeats total trial) | | Builder | 30 min | 50 | 25 | | Studio | 15 min | 200 | 50 | | Studio Pro | 5 min | 1,000 | 100 | | Build For You | 1 min | 10,000 | 500 | Each heartbeat evaluation uses tokens from your billing credits (billed per token against your Chipp credit balance). Silent `HEARTBEAT_OK` check-ins are cheaper than full outreach messages since the AI generates less output. ## Tips for Great Heartbeats - **Be specific in your instructions**: "Check if the user has unresolved support tickets" is better than "Follow up with the user" - **Use your tools**: Design instructions around what your integrations can check -- calendar events, knowledge base updates, CRM data - **Start with daily**: Begin with a daily schedule and adjust based on the analytics in the Statistics section - **Monitor the run history**: The Run History section shows every heartbeat evaluation -- check for patterns in skips, failures, and deliveries - **Use a cheaper model**: Set a model override (e.g., GPT-4.1 mini) for heartbeat evaluations to reduce cost while maintaining quality --- # Database Connections Connect external databases to your AI chatbot so it can query real data during conversations. --- Database Connections lets your AI chatbot query external databases during conversations. Instead of hardcoding answers or uploading CSVs, your AI can run live SQL queries against your PostgreSQL, MySQL, or SQLite database. ## What It Does Your AI gets two tools when a database connection is configured: | Tool | Purpose | |------|---------| | **inspectDatabaseSchema** | Lists tables and columns so the AI knows what data is available | | **queryDatabase** | Executes SQL queries and returns results | The AI automatically calls `inspectDatabaseSchema` first to understand your data structure, then writes accurate queries based on the real schema. This eliminates hallucinated column names. ``` Consumer: "How many orders did we get last week?" ↓ AI calls inspectDatabaseSchema → sees orders table with columns ↓ AI calls queryDatabase → SELECT count(*) FROM orders WHERE created_at > now() - interval '7 days' ↓ AI: "You received 247 orders in the last 7 days." ``` ## Requirements - An externally accessible database (PostgreSQL, MySQL, or SQLite) - A connection string with credentials that have appropriate permissions > **Note:** Database Connections run server-side. Your connection string is encrypted at rest and never sent to the AI model or exposed in API responses. ## Setting Up a Connection **1.** Open Capabilities In the app builder, go to **Brain** > **Integrations** and scroll to the **Database Connections** card. **2.** Add a Connection Click **Add connection** and fill in: - **Connection name**: A friendly label (e.g., "Production Analytics") - **Database type**: PostgreSQL, MySQL, or SQLite - **Connection string**: Your database URL (e.g., `postgres://user:password@host:5432/dbname`) - **Default access level**: Read-only (recommended), Read/Write, or No access - **Data guardrails** (optional): a table allowlist, masked columns, and blocked statements. See [Security Features](#security-features). - **Max rows per query** and **Query timeout (ms)** **3.** Test the Connection Click **Test Connection** in the form, or after saving click the wrench icon on the connection row. This verifies connectivity and discovers your database schema (tables and columns). The schema is saved so your AI knows the exact structure. **4.** Preview Queries (Optional) Click the edit icon, then switch to the **Query Preview** tab. Write SQL queries and see results instantly. This helps you verify the connection works as expected before publishing. ## Security Features Database Connections include multiple security layers to protect your data: ### Encrypted Credentials Connection strings are encrypted with AES-256-CTR before storage. They are decrypted only at query execution time on the server and are never included in API responses, logs, or LLM prompts. ### Read-Only Mode When set to **Read-only** (the default), the database connection enforces read-only mode at the database level: - **PostgreSQL**: each query runs inside a `BEGIN READ ONLY` transaction - **MySQL**: `SET SESSION TRANSACTION READ ONLY` - **SQLite**: `PRAGMA query_only = true` This means even if the AI generates an `INSERT` or `UPDATE`, the database itself rejects it. ### DDL Blocking Dangerous statements are blocked before they reach your database: - `DROP DATABASE` - `DROP TABLE` - `TRUNCATE` - `ALTER TABLE` These are blocked regardless of access level. To change the list, edit **Blocked statements** under **Data guardrails** in the connection form: one statement per line (for example `GRANT` or `DROP SCHEMA`). Each entry is SQL keywords separated by spaces; punctuation is refused. **Reset to defaults** restores the four statements above. ### Row Limits Every query has a configurable maximum row count (default: 1,000). Results exceeding the limit are automatically truncated, preventing your AI from accidentally fetching millions of rows. ### Column Masking Hide sensitive columns from the AI entirely. Masked columns are removed from: 1. The schema description (the AI doesn't know they exist) 2. Query results (values are stripped even if selected) Use this for columns like `password_hash`, `ssn`, `api_key`, or any PII you don't want the AI to see. To mask a column, open the connection and add it to **Masked columns** under **Data guardrails**, one per line, as `table.column` or `schema.table.column` (for example `users.password_hash` or `app.users.ssn`). ### Table Allowlist Restrict which tables the AI can query. When configured, queries referencing tables outside the allowlist are rejected. To set it, open the connection and list the tables under **Table allowlist** in **Data guardrails**, one per line (`orders` or `sales.orders`). After a connection test, the tables Chipp discovered appear below the field: click one to add it. Leave the field empty to allow every table. > **Warning:** The table allowlist uses pattern matching and can be bypassed with advanced SQL constructs (CTEs, subqueries). For true data isolation, use database-level permissions on the connection credentials. The allowlist is a guardrail, not a security boundary. ### SSRF Protection Connection strings are validated to prevent Server-Side Request Forgery: - Private hostnames blocked (localhost, .local, .internal) - DNS resolution checks both IPv4 and IPv6 records for private IP addresses ## Per-Consumer Access Control (RBAC) Each connection has a **default access level** that applies to all consumers. You can override this per consumer: | Access Level | What It Allows | |-------------|----------------| | **Read-only** | `SELECT` queries only | | **Read/Write** | `SELECT`, `INSERT`, `UPDATE`, `DELETE` | | **None** | No access (connection hidden from this consumer) | Per-consumer overrides have no dashboard screen yet. The connection form links here; manage overrides with the API: ```bash # Set a consumer to read/write curl -X PUT /api/applications/{appId}/database-connections/{connectionId}/overrides/{consumerId} \ -H "Content-Type: application/json" \ -d '{"accessLevel": "readwrite"}' # Remove an override (reverts to default) curl -X DELETE /api/applications/{appId}/database-connections/{connectionId}/overrides/{consumerId} ``` ## Multiple Connections You can add more than one database connection per app. When multiple connections are configured: - The AI sees all connection names and their schemas - The AI must specify which connection to query - Each connection has independent access controls, row limits, and column masking This is useful when your data lives across multiple databases (e.g., a user database and an analytics database). ## Query Timeout Queries have a configurable timeout (default: 10 seconds, max: 60 seconds). Long-running queries are killed automatically to prevent your chatbot from hanging. ## Best Practices 1. **Use read-only credentials**: Create a database user with `SELECT`-only permissions. This provides defense-in-depth on top of Chipp's read-only mode. 2. **Mask sensitive columns**: Add `password_hash`, `api_key`, `ssn`, and similar columns to **Masked columns**. The AI won't know they exist. 3. **Set appropriate row limits**: For analytical queries, 1,000 rows is usually sufficient. For lookup queries, consider lower limits (50-100). 4. **Test before publishing**: Use the Query Preview tab to verify your connection and test common queries before making the app live. 5. **Use table allowlists for focus**: Even if the allowlist isn't a security boundary, it helps the AI focus on relevant tables and reduces confusion from unrelated schemas. ## Supported Database Types | Database | Connection String Format | Notes | |----------|------------------------|-------| | **PostgreSQL** | `postgres://user:pass@host:5432/dbname` | Most popular. Full schema discovery via `information_schema`. | | **MySQL** | `mysql://user:pass@host:3306/dbname` | Schema discovery via `information_schema`. | | **SQLite** | Relative file path (e.g., `data/app.db`) | File-based. Must use relative paths for security. | > **Tip:** If your password contains special characters (`#`, `*`, `@`), URL-encode them in the connection string. For example, `p@ss#word` becomes `p%40ss%23word`. ## Billing Database queries are included in your LLM token billing. There is no separate per-query charge. You only pay for the AI tokens used to process and respond to the query results. ## Troubleshooting ### "Connection must not point to private hosts" Your database must be publicly accessible. Chipp's servers cannot reach databases on private networks (localhost, 10.x.x.x, 192.168.x.x). **Fix**: Ensure your database has a public IP or is accessible through a connection proxy. ### "Schema not yet discovered" The connection was saved but hasn't been tested. Click the wrench icon to test the connection and discover the schema. ### "Table not in the allowed list" Your table allowlist is blocking the query. Open the connection and either add the table to **Table allowlist** or clear the field to allow every table. ### "Cannot execute INSERT in a read-only transaction" The connection is set to read-only mode. Change the default access level to "Read/Write" if write operations are needed, or set a per-consumer override for specific users. ### Query timeout Complex queries may exceed the timeout. Increase the timeout in connection settings (up to 60 seconds), or optimize the query with indexes and `LIMIT` clauses. --- # Agent-to-Agent Links Build a team of specialist AI agents that automatically delegate questions to each other. --- Agent-to-Agent Links let one agent automatically delegate questions to specialist agents in your workspace. Your main agent acts as an orchestrator -- when a consumer asks something a linked agent specializes in, it passes the question to that specialist and incorporates the response. > **Note:** Agent links require a Builder plan or higher. > href="https://build.chipp.ai/plans" > target="_blank" > rel="noopener noreferrer" > > > > Upgrade to Builder → > ## How It Works 1. You link specialist agents to your main agent 2. Linked agents are automatically registered as tools during consumer chat 3. When your agent decides a specialist would provide a better answer, it calls that agent 4. The specialist responds using its own system prompt, model, and knowledge base 5. Your main agent incorporates the specialist's response into its answer to the user The consumer sees a seamless conversation -- they don't need to know multiple agents are involved. ## Setting Up Agent Links **1.** Open Agent Tools Go to your app's **Brain** page → **Integrations** tab. Find the **Agent Tools** card. **2.** Add Linked Agents Click **Add agent tools** (or **Add agent** once you have linked one). The **Link Agent Tools** modal shows the agents in this app's workspace. Switch to **All workspaces**, or pick another workspace, to link agents from elsewhere in your organization. Click an agent to link it. **3.** Test It In the chat preview, ask a question that falls within a linked agent's specialty. You should see the main agent delegate to the specialist and incorporate its response. To remove a linked agent, click the **x** button next to its name in the Agent Tools list. ## What Gets Passed to Specialists When a linked agent is called: | Passed | Not Passed | |--------|-----------| | The specific question or request | Consumer's conversation history | | Specialist's system prompt and model | Consumer memory or profile | | Specialist's knowledge base (RAG) | Uploaded files | | Web search (if enabled on specialist) | Billing or subscription info | Each call is a single turn -- the specialist responds once and returns the result. There's no multi-turn conversation between agents. Per-user OAuth credentials (Google Drive, Outlook, etc.) are **not** shared with linked agents by default. If you want consumers to connect an integration once on the hub agent and have linked agents in the same workspace reuse it, turn on the hub agent's **Share connected credentials with linked agents** toggle in the Agent Tools card (`shareConsumerCredentialsWithLinkedAgents`). ## Structured Response Contracts By default a specialist replies in free-form text. The calling agent can instead declare a **response contract**: a set of named fields (each with a description and an optional type) that the specialist must return. This happens automatically when the calling model decides it needs a machine-readable answer, and requires no configuration. When a contract is declared: - The specialist is told it is being called programmatically and must not reply conversationally. - Its answer comes back as a JSON object with exactly the declared fields (`{"status": "ok", "data": {...}}`). - If the specialist is missing information it needs, it pushes back with `{"status": "needs_clarification", "question": "..."}` instead of guessing, and the calling agent can follow up or ask the user. - Fields the specialist genuinely cannot determine come back as `null` rather than fabricated values. Example: a Butler agent asked "what important emails did I get in the past 24 hours?" can call an inbox specialist with a contract like `[{name: "important_emails", type: "object[]", description: "Sender, subject, and a one-line reason each email matters"}, {name: "total_count", type: "number", description: "Total emails received"}]` and receive structured data it can reason over, instead of prose it has to re-parse. ## Step Limit for Linked Agents A linked agent works in steps. A step is one model turn that can use tools (a search, a record lookup, a file read). By default a linked agent gets **5 steps** per call. If it is still working at the limit, it is forced to answer with what it has, and its reply is marked as possibly incomplete. If a specialist needs more steps (for example it searches records, pages through results, then writes a summary), raise its limit: | Where | How | |-------|-----| | All linked agents of one app | **Brain** page → **Integrations** tab → **Agent Tools** → **Step limit for linked agents** | | One linked agent | The **Steps** box next to that agent in the Agent Tools list | | Alchemist | Ask it to set the step limit, or use `update_app_settings({ linkedAgentMaxIterations: 12 })` | Things to know: - The limit is a whole number from **1 to 25**. The default is **5**. Leave the box empty to use the default. - The setting belongs to the agent that **makes** the call (your main agent), not to the specialist. - A value on one linked agent wins over the value for the whole app. The app value wins over the default. - It applies right away. You do not need to publish again. - **Agents calling agents:** only the first hop, your main agent calling a specialist, can use a limit above 5. When a specialist calls another linked agent, that second call is always held to at most 5 steps. - Higher limits can use more tokens. Usage is billed to your organization as usual, so raise the limit only for agents that need it. ### Knowing when an answer was cut off Every linked-agent reply includes a small status block that your main agent can read. It says whether the specialist hit its step limit (`truncated`), how many steps it used (`iterationsUsed`), the limit it ran with (`effectiveBudget`), and why it stopped (`finishReason`: `completed`, `max_iterations`, `error`, `refused_payment`, `invalid_contract` or `error_before_loop`). ```json { "completion": { "truncated": true, "iterationsUsed": 5, "effectiveBudget": 5, "budgetSource": "default", "finishReason": "max_iterations", "callDepth": 1 }, "response": "Here is what I found so far. [Note: this specialist agent reached its internal step limit ...]" } ``` The short note at the end of a cut-off reply is still there, so older prompts keep working. For new instructions, tell your main agent to look at `completion.truncated` instead of the note: for example, "If `completion.truncated` is true, ask the specialist a narrower question or tell the user the answer may be incomplete." ## Delegation Topology Together, your agents and their links form a **delegation topology**: the directed graph of who can call whom, and the contracts governing each hand-off. You can ask the Alchemist copilot to build one for you in a single step ("create a client-onboarding system with a front-door agent, a document collector, and a compliance checker"), or ask it "how are my agents wired together?" to read your workspace's current topology back as nodes, edges, and hub/specialist roles. ## Delegation Depth Linked agents can themselves have linked agents, enabling multi-hop delegation: - **Depth 0:** Consumer talks to your main agent - **Depth 1:** Main agent calls a specialist - **Depth 2:** That specialist calls one of its linked agents - **Depth 3:** Maximum nesting depth (no further delegation) This prevents infinite recursion while supporting reasonable multi-hop scenarios. Calls below the first hop are held to the default of 5 steps each (see [Step Limit for Linked Agents](#step-limit-for-linked-agents)). ## Use Cases | Scenario | Setup | |----------|-------| | **Customer support triage** | Main agent routes billing questions to a billing expert, refunds to a refunds agent, technical issues to support | | **Multi-domain expertise** | Finance agent delegates tax questions to a tax specialist, accounting to an accounting specialist | | **Department delegation** | HR chatbot sends benefits questions to benefits specialist, payroll to payroll specialist | | **Skill-based routing** | Marketing agent asks product knowledge agent for details before composing responses | ## Billing When a linked agent is called, token usage is billed to the **source app's organization** (the app the consumer is talking to). There's no separate fee for agent-to-agent calls -- it's part of your standard LLM token billing. ## Tips - **Write clear descriptions** for your specialist agents. Your main agent uses the description to decide when to delegate, so make it specific. - **Keep specialists focused.** A "billing expert" agent with a tailored system prompt and billing knowledge base will outperform a general-purpose agent. - **Test delegation patterns.** In the chat preview, ask questions that should trigger delegation and verify the right specialist handles them. ## Troubleshooting **Agent not delegating?** - Check that the specialist agent is linked in the Agent Tools card (Brain → Integrations tab) - Verify the specialist's description clearly indicates its specialty - The main agent may handle the question itself if it has sufficient knowledge **Wrong specialist being called?** - Update specialist descriptions to be more specific about their domains - Review your main agent's system prompt -- you can add instructions about when to delegate **Specialist reply says it reached its step limit?** - Raise the step limit for that agent (or for all linked agents) as described above, up to 25 - Or ask a narrower question so it can finish in fewer steps - If the cut-off agent is a second-level agent (called by another linked agent), its limit is fixed at 5 **Slow responses?** - Each delegation adds a round trip to another LLM call - Consider whether the specialist adds enough value to justify the latency - Avoid deep nesting (depth 2-3) unless necessary --- # Watched Folders (Chipp Desktop) Point a folder on your Mac at any of your Chipp agents and every document you drop there becomes agent knowledge automatically. --- Keeping an agent's knowledge fresh is the single biggest chore in running one. You upload ten documents at setup, the business moves on, and six months later your agent is confidently answering from last quarter. Watched Folders removes the chore. In the Chipp desktop app, point a local folder at one of your agents. From then on, every supported document you drop into that folder syncs to the agent's knowledge automatically, and it is available to the agent everywhere: web, mobile, Slack, WhatsApp, every channel it lives on. ## Setting it up 1. Open the Chipp desktop app and click the **Chipp** chip in the header. 2. Click **Sign in with Chipp** if you have not already connected your account (your browser opens to approve access; there are no API keys to manage). 3. Under **Watched Folders**, click **Add folder...**. 4. Enter the folder path (for example `~/Clients/Acme`), choose the agent it should feed, and click **Watch folder**. That is it. The desktop checks the folder about once a minute. When a new or updated document appears, you will see a small notification confirming the sync. ## What syncs - Documents: PDF, DOCX, DOC, TXT, Markdown, CSV, JSON, XLSX, XLS - Audio: MP3, WAV, M4A, OGG, FLAC (transcribed on ingestion) - Files up to 25 MB each Updated files replace their earlier version in the agent's knowledge, so re-saving a document keeps the agent current rather than piling up duplicates. Hidden files are never touched, and the sync only ever reads inside your home folder. ## Ideas - A consultant's per-client deliverables folder, so each client agent always knows the latest work. - A founder's board-materials folder feeding an internal Q&A agent. - A support lead's policy-docs folder keeping the customer-facing agent honest after every policy change. - An exported-meeting-notes folder, so your agent can answer "what did we decide about pricing?" ## Privacy and limits The desktop app only reads folders you explicitly add, only inside your home directory, and uploads only the supported file types listed above. Nothing else on your machine is scanned. Syncs use the same authenticated connection as your Chipp session, and you can stop watching a folder at any time from the same panel (click the **x** next to it). You can watch up to 20 folders. --- # Message Tagging Automatically detect and respond to specific types of user messages using AI-powered semantic matching --- Message tags are one of the most powerful features in Chipp. They let you automatically detect specific types of messages and take action, whether that's routing to a human, blocking harmful content, or tracking purchase intent. ## What Can You Do with Tags? Tags unlock a wide range of automation possibilities. Here are just a few: ## How Tag Detection Works Unlike simple keyword matching, Chipp understands the meaning behind messages. New tags use the Jev classifier: Jev decides from the tag's name and description, so a new tag works right away with no example phrases. Tags created before Jev use **semantic similarity** against their example phrases. Either way, your tags catch variations and paraphrases you never explicitly defined. ### Why Semantic Matching Matters Traditional keyword-based systems require you to anticipate every possible way someone might phrase a request. With semantic matching: - "I want to talk to a human" matches "Can I speak with a real person?" - "What's the price?" matches "How much does this cost?" - "I'm frustrated" matches "This is really annoying" You define a few example phrases, and the AI understands the underlying intent. ## Getting Started Ready to set up your first tag? Follow this step-by-step guide: ## Tag Configuration Options Each tag has several settings you can customize: ### Tag Name Give your tag a clear, descriptive name. You'll see this in your analytics and when reviewing chat history, so make it easy to understand at a glance. **Good names:** "Human Escalation", "Pricing Question", "Complaint" **Bad names:** "Tag 1", "Important", "Check" ### Description Describe exactly when the tag should trigger. For new (Jev) tags, Jev decides from the name and this description, so be specific. ### Example Phrases Add 3-5 phrases under "TRAIN THIS TAG · POSITIVE EXAMPLES" that represent the type of message you want to detect. Older similarity-based tags need these to work. For Jev tags they are optional boundary material. Focus on variety: ``` Good examples for "Human Needed": - "I need to talk to a human" - "Can I speak with a real person?" - "Connect me to support" - "I want to talk to someone" Less effective (too similar): - "Talk to human" - "Speak to human" - "Human please" - "Get me a human" ``` ### Detection Sensitivity The "Detection sensitivity" slider runs from **Strict** to **Sensitive** and controls how readily the tag triggers. A higher percentage means the tag triggers more readily: | Slider | Label | Trade-off | |--------|-------|-----------| | 0-29% | Very strict | Precise matching only, may miss variations | | 30-69% | Balanced | Good starting point | | 70-100% | Very sensitive | Catches more variations, more false positives | **Tip:** New tags start at 50% (Balanced). Adjust based on what you see in your chat history. ### Static Text Response (Optional) For safety or compliance tags, you can replace the AI's response entirely when a tag is detected. Enter the text in the "Static text response" field (leave it empty to use the AI response). You can also turn on "Freeze conversation" to disable input after the static response. This is useful for: - **Harmful content:** Block and provide a polite refusal - **Off-topic requests:** Redirect to your app's purpose - **Sensitive topics:** Provide specific guidance or disclaimers When you add a static text response, the AI won't generate anything: your exact text will be shown instead. ## Best Practices ### Start Small Begin with 2-3 high-value tags rather than trying to cover every scenario. You can always add more as you learn what your users are asking. ### Review Matches Regularly Check your tag matches in the chat history to spot false positives and missed detections. This helps you tune your sensitivity and add better example phrases. ### Use Specific Examples The more specific and varied your example phrases, the better the detection. Generic phrases lead to more false positives. ### Don't Over-Block Only use blocking responses when absolutely necessary. For most tags, it's better to let the AI respond naturally while you track the conversation. ## Common Tag Configurations Here are some popular tag setups to get you started: ### Customer Support Bot | Tag | Purpose | Blocking? | |-----|---------|-----------| | Human Needed | Route frustrated users to support | No | | Refund Request | Flag for manual review | No | | Positive Feedback | Track happy customers | No | ### Sales Assistant | Tag | Purpose | Blocking? | |-----|---------|-----------| | Purchase Intent | Identify hot leads | No | | Pricing Question | Track interest | No | | Competitor Mention | Monitor positioning | No | ### Knowledge Base | Tag | Purpose | Blocking? | |-----|---------|-----------| | Off-Topic | Redirect to purpose | Yes | | Complex Question | Flag for follow-up | No | | Feedback | Collect suggestions | No | ## Viewing Tag Analytics Once your tags are active, you can see them in action: 1. **Chat History:** Each message shows any tags that were detected 2. **Tag Detail View:** Click on a tag to see all matches, sorted by recency 3. **Remove False Positives:** Click the X on any incorrectly tagged message to improve future detection ## Advanced Tips ### Combine with Custom Actions Use tags as triggers for more complex workflows. When a tag is detected, you could: - Send a notification to Slack - Create a ticket in your CRM - Update a spreadsheet - Trigger an email ### Multiple Tags per Message A single message can trigger multiple tags. For example, "I want a refund and need to speak to someone" might trigger both "Refund Request" and "Human Needed." ### Tag Categories Organize related tags with consistent naming prefixes: - `Support: Human Needed` - `Support: Complaint` - `Sales: Pricing Question` - `Sales: Demo Request` ## Negative Examples: Teaching Tags What NOT to Match By default, tags learn only from positive examples: phrases that *should* trigger. For most use cases this works well, but when your tag guards a hard compliance boundary (like "block external data comparisons" or "prevent off-label claims"), a legitimate message can look almost identical to a prohibited one. ### When to Use Negative Examples Negative examples are most valuable in three scenarios: 1. **Semantic Overlap:** Your positive examples ("Compare our rate to published literature") are semantically very similar to legitimate messages ("Compare our rate across patient subgroups"). Raising the sensitivity threshold alone can't separate them. 2. **Compliance Boundaries:** Tags that guard strict regulatory or safety rules where false negatives (missing a prohibited intent) are worse than false positives, but missed legitimate uses break user experience. 3. **Calibration Precision:** You've tuned a tag with "Test a message" (see below) and consistently see one type of false positive that thresholds can't filter. ### How Negative Examples Work Chipp's semantic matching computes cosine similarity between an incoming message and all your tag's examples, both positive and negative. A message triggers the tag if its best match (highest similarity to any example) beats the configured threshold. **Key insight:** Negative examples compete directly against positive examples in the same semantic space. When a message is semantically close to both a positive and a negative example, the tag resolves toward whichever example it's more similar to. This is why a couple of well-chosen negatives can improve precision where thresholds alone cannot. **Guardrail:** If a message is equally similar to a positive and negative example (a tie), the tag triggers: fail-safe behavior. When in doubt, block. ### Example: Pharma Compliance Boundary A tag needs to block external/published-literature comparisons ("What is our rate compared to the published literature?") while allowing legitimate cohort analyses: **Positive examples (must trigger):** - "How does our rate compare to published literature?" - "What does the literature say about this rate?" - "How do we stack up against industry benchmarks?" **Negative examples (must NOT trigger):** - "How does our rate differ across patient subgroups?" - "Compare our rate between males and females in the cohort" - "What's the misdiagnosis rate in our patient population?" With the negatives in place, the classifier learns that "compare ... to literature/benchmarks/external" is the true signal, not comparison in general. Testing revealed that this fixture (6 prompts at 0.33 and 0.5 sensitivity thresholds) achieves clean separation only with negatives. Thresholds alone catch either all positives and all negatives, or none of either. ### Creating and Managing Negative Examples 1. Open the tag editor and scroll to "NEGATIVE EXAMPLES · MUST NOT TRIGGER" 2. Add 2-5 phrases that are similar to your positives but must never trigger 3. Focus on the specific semantic boundary you're guarding (e.g., "external comparisons" vs. "within-cohort comparisons") 4. Use **"Test a message"** (below) to validate that your negatives actually prevent false positives 5. If separability still isn't clean, add more negatives targeting the boundary, or split into more specific tags ## Calibrating Tags with "Test a Message" The "Test a message" panel in the tag editor lets you score any message against the tag in real-time, showing: - **Match score:** Numeric similarity (0-1) to the closest example - **Threshold:** Your configured sensitivity level - **Would trigger:** Boolean outcome for this message This is invaluable for calibration: - Draft your positives and negatives, then test real prompts from your chat history - If a legitimate message is scoring too high (near the threshold), add a negative example close to it - If a prohibited message is scoring too low (missing true positives), refine your positive examples for more specificity - Iterate until you see clean separation between intended positives and negatives The test does *not* generate a response, mutate conversation state, or create a permanent record: it's purely diagnostic. ## Troubleshooting ### Tags Aren't Detecting Anything - Move the sensitivity slider toward Sensitive - Make the description more specific, or add more varied example phrases - Check that the tag is enabled ### Too Many False Positives - Move the sensitivity slider toward Strict - Make example phrases more specific - Remove overly generic examples ### Tags Detecting the Wrong Things - Review your example phrases for unintended patterns - **Use negative examples**: See the "Negative Examples" section above. This is especially effective for hard compliance boundaries where legitimate messages are semantically similar to prohibited ones. - **Test before deploying**: Use "Test a message" (see "Calibrating Tags" above) to validate your positive/negative/threshold combination against real prompts before enabling the tag live. - Move the sensitivity slider toward Strict if you're getting false positives on completely unrelated topics - Consider splitting into more specific tags if you have multiple distinct intents ## Next Steps Now that you understand message tagging, try setting up your first tag: 1. Think about what user messages you most want to detect 2. Create a tag with a precise description (and, optionally, 3-5 good example phrases) 3. Start at the default 50% sensitivity 4. Monitor your chat history for a few days 5. Tune based on what you observe Tags become more valuable over time as you refine them based on real user interactions. Start simple, iterate often, and you'll build a powerful automation layer for your AI app. ## Using with MCP You can manage tags programmatically using the Chipp MCP Server, including AI-powered utterance generation. ### Available Tools | Tool | Description | |------|-------------| | `list_tags` | List all tags for an app | | `create_tag` | Create a new tag with a description, examples, and actions | | `update_tag` | Update tag name, description, examples, or actions | | `set_tag_examples` | Replace a tag's example phrases | | `add_tag_examples` | Append example phrases to a tag | | `delete_tag` | Remove a tag | | `list_tag_instances` | View messages that matched a tag | | `remove_tag_instance` | Remove a false positive match | | `generate_utterances` | AI-generate training phrases for a tag (up to 100 per call) | ### Example Prompts ``` "Create a tag called 'pricing_intent' for my sales bot" "Generate 50 utterances for detecting refund requests" "Show messages that matched the 'human_needed' tag" "Remove the false positive from tag instance xyz" ``` ### Workflow: AI-Powered Tag Training ``` You: Create a tag for detecting pricing questions in my B2B sales bot AI: [Calls create_tag] Created tag "pricing_intent". Would you like me to generate training utterances? You: Yes, generate 100 varied examples for B2B software pricing AI: [Calls generate_utterances with count=100 and a tag_description about B2B software pricing] Generated 100 utterances including: - "How much does your enterprise plan cost?" - "What's the pricing for 100 users?" - "Do you offer volume discounts?" - "Is there a free trial available?" ... AI: [Calls add_tag_examples] Saved to tag "pricing_intent". The tag is now active. ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- # Lead Generation Forms Collect user information before starting a conversation with customizable lead capture forms. --- Lead generation forms let you collect user information when people sign up to chat with your AI. In the builder this feature is called **Signup Fields**: extra fields (phone, company, role, or your own questions) shown on your app's sign-up form. Values are stored on the user's account and shared with your AI. ## Why Use Lead Forms? | Benefit | Description | |---------|-------------| | **Qualify leads** | Collect contact info before investing AI resources | | **Personalize conversations** | Use collected data to customize responses | | **Build your list** | Export users and their answers as a CSV | | **Gate access** | Require sign-up (and required fields) before chat access | ## Setting Up a Lead Form **1.** Turn on sign-up Go to your app's **Launch** > **Access** page and choose **Required Sign-up**, **Encouraged Sign-up**, or **Restricted Access**. Signup Fields are hidden when the app is set to **Open Access**, because there is no sign-up form to attach them to. **2.** Enable Signup Fields On the same page, find the **Signup Fields** card and turn on its switch. **3.** Add a heading and helper text (optional) Enter an optional heading (for example, "Tell us about yourself") and optional helper text shown above the fields. Use these to explain why you're collecting information. **4.** Add fields Click a preset button to add a field: - **+ Phone** - **+ Company** - **+ Role** - **+ Custom field** You can rename any field's label and change its type. **5.** Set required fields Check **Required** next to each field that users must fill in. Use the arrow buttons to reorder fields and the trash icon to delete one. **6.** Test it Changes save automatically. Open your app and sign up as a new user to see the form. ## Field Types Each field has one of these types: | Type | Description | |------|-------------| | **text** | Free-form text (up to 2,000 characters) | | **email** | Must be a valid email address | | **phone** | Digits, spaces, and `+ - ( ) .` only | | **number** | Numeric value | | **select** | A dropdown. Enter the options as a comma-separated list (up to 50 options) | A form can have up to 20 fields. The sign-up form itself already collects the user's email address, so you do not need to add an email field. ## Viewing and Exporting Leads Go to **Insights** > **Consumers** to see the users who signed up. Click **Export CSV** to download them. The export includes a column for each of your Signup Fields. ## Managing Your Form ### Enable/Disable Turn off the switch on the **Signup Fields** card to stop showing the fields without deleting them. ### Delete a Field Click the trash icon next to a field to remove it. ## Using Lead Data in Conversations Collected information is available to your AI during the conversation. Your AI can use the submitted information to personalize responses. ## Best Practices ### Keep Forms Short Every additional field reduces completion rates. Only ask for what you truly need. ### Make Most Fields Optional Required fields create friction. Consider making phone and company optional unless critical to your use case. ### Explain Why Use the helper text to tell users why you're collecting their information: ``` "To get started, we'll need a few things from you so we can better assist you." ``` ## Troubleshooting ### Form Not Appearing 1. Verify your app's access mode is not **Open Access** 2. Verify the **Signup Fields** switch is on 3. Make sure at least one field is added 4. If **SSO-only login** is enabled, Signup Fields cannot be collected. Disable SSO-only to show them. 5. Clear browser cache and test in incognito --- # Alchemist: Your Team Add your agents to a team, and the Alchemist hands them work, shows you what they did, and asks before anything is changed. --- The Alchemist can work with your other agents. Put them on your team, and the Alchemist hands each one the part of the job that belongs in its world: its data, its integrations, its project. ## Build your team Above the Alchemist's message box is the **Your team** bar. Click **+** and switch on the agents you want. You can also ask: "Add Support Bot and Cody to my team." A team holds up to 12 agents. You can add any agent you can edit, in any of your organizations. ## Hand off work Ask in plain words: "Ask Support Bot how many refunds we gave last week." Or click the agent in the team bar and choose **Delegate a task**. The Alchemist writes a full brief and sends it. A card shows the agent, what it was sent, each step it takes, the time and the cost. The agent runs as you, with its own tools and rules. It sees only the brief, never your other conversations or memories, and it never writes to your memory. ## You approve the changes When an agent wants to do something that needs approval (file a ticket, run an action you marked "requires approval"), it does not do it. The request appears on the card with **Approve** and **Reject**. When you decide, the agent picks up where it stopped. ## Long jobs If a job takes more than a minute, the Alchemist tells you it is still working and moves on. When the job finishes, the Alchemist reports back by itself, and your phone gets a notification if you use the Chipp Builder app. Click **Cancel** on a card to stop a job; anything it was waiting on is rejected. ## What it costs An agent's work bills to that agent's organization, like a chat with it. The usage page shows it as **Alchemist Team Delegation**, with the name of the person who asked, so an admin can see who used what. ## Limits - Up to 3 jobs at once. - Up to 30 new jobs an hour. - A job stops after 20 minutes, 30 steps, or $3.00 of usage. - Files from one organization are never sent to an agent in another. --- # Multilingual Apps Configure your app's display language so the AI, the chat UI, and emails all speak your audience's language. --- Chipp apps are multilingual by default. As a builder, you pick the **Display Language** for your app, and the choice flows through everything your consumers see: the AI's responses, the chat UI chrome, transactional emails, and the document direction (left-to-right or right-to-left). ## Supported Languages | Code | Language | Code | Language | |------|----------|------|----------| | `EN` | English | `RU` | Russian | | `ES` | Spanish | `JA` | Japanese | | `PT` | Portuguese | `KO` | Korean | | `FR` | French | `ZH` | Chinese | | `DE` | German | `AR` | Arabic *(RTL)* | | `IT` | Italian | `HI` | Hindi | | `NL` | Dutch | `TR` | Turkish | | `PL` | Polish | `VI` | Vietnamese | | `TH` | Thai | `ID` | Indonesian | | `MS` | Malay | `FIL` | Filipino | | `HE` | Hebrew *(RTL)* | `UK` | Ukrainian | | `CS` | Czech | | | 23 languages are supported. English is the source/fallback dictionary. 19 others ship with translations for the most common consumer-facing strings. Hebrew, Ukrainian, and Czech do not have chat UI translations yet, so their UI strings show in English while the AI still replies in the chosen language. Any missing key gracefully falls back to English. Arabic and Hebrew are the right-to-left languages in the supported set today; if you need Farsi, Urdu, or another language, email us at support@chipp.ai. ## What Display Language Affects Setting the Display Language updates four things at once: - **The AI's replies.** Chipp injects a `Respond in .` directive into the system prompt, so the AI answers in the chosen language even when your prompt is authored in English. - **The consumer chat UI.** The auth flow, history sheet, in-chat menu, file storage sheet, install prompts, package modal, and credit-purchase flow are all translated. - **Transactional emails.** OTP codes, password resets, and welcome emails go out in the chosen language. Whitelabel customizations still take priority where set. - **Document direction and locale tags.** The page's `` and `` are set so screen readers, on-screen keyboards, and the chat input all behave correctly. Turning on right-to-left flips the layout. ## Setting the Default Language (Builder) **1.** Open Settings Open your app, go to the **Launch** group, and click **Settings**. **2.** Pick the Display Language Scroll to the **Language** card and pick a language from the **Display Language** dropdown. **3.** Set Text Direction Picking a language sets the direction for you: Arabic and Hebrew switch **Right-to-left text direction** on, and every other language switches it off. To override it, change the checkbox after you pick the language. For example, untick it for a left-to-right layout in Arabic, or tick it for a right-to-left layout in any language. **4.** Done -- Saves Live Language changes are live-on-save. You don't need to publish a new version of the app -- the next consumer message already uses the new language. ## Tips for Multilingual Apps | Tip | Why It Helps | |-----|--------------| | Author the system prompt in English | The AI translates output into the consumer's chosen language. English prompts are easier to maintain, and large models work best with them. | | Localize the welcome message and conversation starters | Starters are static text -- they don't auto-translate. Write them in the target language so first impressions match. | | Mix-language knowledge sources are fine | Knowledge sources can be in any language. The AI reads them as-is and translates retrieval results into the consumer's language. | | Consider Arabic typography | Arabic apps benefit from a font that supports Arabic glyphs and proper kerning. Set a custom font in **Style Studio** if needed. | | Voice mode | The voice agent does not yet respect the Display Language toggle -- if you want voice replies in a specific language, ask for it explicitly in your system prompt. See [Voice Cloning](/docs/guides/voice-cloning) for caveats around accent and TTS providers. | ## Limitations - The Chipp **builder dashboard itself is English-only**. The consumer chat experience is translated; the dashboard you log into to configure the app is not. - Conversation starters, custom CTAs, welcome messages, and any text you author manually are **not auto-translated**. Write them in the target language. - Some hosted-integration error messages (Google, Microsoft, etc.) come from the third-party provider and are not translated by Chipp. ## Related - [Setup card](/docs/guides/maximize-chipp-capabilities): author conversation starters, system prompt, and welcome message - [Embed Widget](/docs/guides/embed-widget): the embedded widget inherits your app's Display Language - [Voice Cloning](/docs/guides/voice-cloning): language and accent in voice mode --- # Understanding AI Evaluations Learn how to test your AI chatbot before launching it to customers. Evals help you know exactly what your AI will say in any situation, so you can ship with confidence. --- You've built an AI chatbot. It looks great in demos. But how do you know it won't embarrass you in front of real customers? What if it hallucinates incorrect pricing? What if it gives wrong business hours? What if it goes completely off-topic? This is where **evaluations** (evals) come in. Think of evals as automated QA testing for your AI. Before your chatbot goes live, you can verify it gives the right answers to important questions. ## Why Evals Matter Imagine you run a SaaS company. A customer asks your AI chatbot: "What's your pricing?" Without evals, you might discover too late that your AI confidently stated "\$99/month" when your actual pricing is "\$29/month." That's not just embarrassing - it can damage trust and create legal issues. With evals, you can: 1. **Define test cases** - Questions your AI should handle correctly 2. **Specify expected answers** - What the correct response should be 3. **Run automated checks** - Before every deployment 4. **Catch problems early** - Before customers ever see them > **Note:** Evals are like unit tests for traditional software, but for AI responses. They let you ship with confidence. ## Prerequisites for Each Evaluation Type Not all evaluation types work for all chatbots. Here's what each one requires: | Evaluation Type | Requirements | |----------------|--------------| | **Factuality** | None - works with any chatbot | | **Faithfulness** | Requires knowledge sources (documents, URLs) | | **Answer Relevancy** | None - works with any chatbot | | **Context Relevancy** | Requires knowledge sources (documents, URLs) | | **Comprehensive** | Runs all four metrics when the app has knowledge sources; otherwise only Factuality and Answer Relevancy | > **Warning:** If your chatbot doesn't use a knowledge base, stick with **Factuality** and **Answer Relevancy**. The other metrics evaluate how well your AI uses retrieved documents: without documents to retrieve, those scores won't be meaningful. ## The Four Types of Evaluations Chipp uses an "LLM-as-Judge" approach, where a separate AI model evaluates your chatbot's responses. This is like having an expert reviewer automatically grade every answer. There are four evaluation types, each measuring something different: ### 1. Factuality - "Is the answer correct?" Factuality is the most straightforward evaluation. You provide a question, the expected correct answer, and then check if your AI's response matches. This doesn't require exact word-for-word matching - the system understands semantic equivalence. "We're open 9 AM to 5 PM" and "Our hours are nine in the morning until five in the evening" would both pass. **Use Factuality when:** - You have specific, known-correct answers - Testing objective facts (pricing, hours, policies) - Verifying your AI learned from training correctly > **Note:** **Tip for Expected Answers**: Keep your expected answers focused on the key facts. The evaluation compares semantic content, not word count. If your AI gives a more comprehensive answer than expected, it may score lower because it includes "extra" information. > > **Example:** > - Expected: "Our return policy is 30 days" > - AI Response: "Our return policy is 30 days for all products. Items must be unused and in original packaging." > - Score: ~60% (the AI is correct but added details not in the expected answer) > > For best results, either make expected answers comprehensive, or use Faithfulness to test that responses are grounded in your knowledge base. ### 2. Faithfulness - "Is it making things up?" Faithfulness checks if your AI is "hallucinating" - making up information that isn't in its knowledge base. This is critical when your chatbot uses uploaded documents or a knowledge base. For example, if your knowledge base says "Returns accepted within 30 days" but your AI responds "Returns accepted within 90 days with free shipping," that's a faithfulness failure. The AI added details that don't exist in the source material. **Use Faithfulness when:** - Your chatbot uses a knowledge base or uploaded documents - You want to prevent hallucinations - Accuracy is critical (legal, medical, financial content) ### 3. Answer Relevancy - "Did it answer the question?" Answer Relevancy checks if the AI actually answered what was asked. Sometimes an AI will give a perfectly accurate response that has nothing to do with the question. "How do I reset my password?" shouldn't be answered with "Our company was founded in 2015 with a mission to revolutionize customer service..." **Use Answer Relevancy when:** - Users complain the AI doesn't answer their questions - You want responses to stay focused - Your AI tends to be verbose or go off-topic ### 4. Context Relevancy - "Did we retrieve the right information?" Context Relevancy is specifically for RAG (Retrieval-Augmented Generation) systems - chatbots that search through documents to find relevant information before answering. This eval checks if the search step worked correctly. Even if your AI gives a perfect response, if it retrieved the wrong documents, that's a problem waiting to happen. **Use Context Relevancy when:** - Debugging why your RAG chatbot gives wrong answers - Your knowledge base is large and complex - You want to optimize document retrieval > **Warning:** **Important Distinction**: Context Relevancy evaluates your document retrieval, not your AI's answer. A low score means your RAG system is pulling irrelevant documents, even if the AI gives a good answer despite having poor context. > > If you see low Context Relevancy but good Answer Relevancy, focus on improving your knowledge base organization or embedding quality rather than your AI's instructions. ## Choosing the Right Evaluation ## Running All Evaluations Together For the most thorough testing, you can select **Comprehensive** as your evaluation method. This runs all four evaluations on each test case and produces scores for each metric. If your app has no knowledge sources, Comprehensive skips Faithfulness and Context Relevancy. **When to use Comprehensive:** - Initial chatbot testing before launch - After major knowledge base updates - Debugging complex answer quality issues **Understanding combined results:** When running Comprehensive, a test case passes if the AVERAGE of its metric scores meets the 70% threshold. A single weak metric can be carried by strong ones, so check the per-metric scores too, or run individual evaluation types when one metric matters most. | Metric | What Failure Means | |--------|-------------------| | Factuality fails | Answer doesn't match expected content | | Faithfulness fails | Answer contains hallucinated information | | Answer Relevancy fails | Answer doesn't address the question | | Context Relevancy fails | RAG retrieved irrelevant documents | > **Note:** **Pro Tip**: When using Comprehensive, don't be surprised if Context Relevancy scores lower than other metrics. Retrieval is the hardest part of RAG systems. If your other metrics pass but Context Relevancy fails, your chatbot is likely working well despite imperfect search results. ## Why Factuality is the Best Starting Point If you're new to evals and not sure where to start, **choose Factuality**. Here's why: 1. **It's intuitive** - You just provide questions and correct answers 2. **No setup required** - Works with any chatbot, with or without a knowledge base 3. **Clear pass/fail** - Easy to understand if something's wrong 4. **Most common issues** - Catches the problems that matter most to customers The other evaluation types (Faithfulness, Answer Relevancy, Context Relevancy) are more specialized. They're powerful for specific use cases, but Factuality covers the most ground for most chatbots. > **Success:** **Quick Start**: Create 10-20 test cases covering your most important questions. Run Factuality evaluation. Fix any failures. Repeat before every major change to your chatbot. ## Creating Effective Test Cases A good evaluation suite includes: ### 1. Happy Path Cases Questions your AI should answer perfectly. These are the bread-and-butter interactions: - "What are your business hours?" - "How much does it cost?" - "How do I contact support?" ### 2. Edge Cases Tricky questions that might trip up your AI: - Ambiguous questions - Questions about things not in your knowledge base - Multi-part questions ### 3. Red Lines Things your AI should never say: - Competitor comparisons you don't want made - Promises you can't keep - Sensitive topics you want avoided ## The Eval Workflow Here's how to integrate evals into your chatbot development: **1.** Create test cases - Start with your most important customer questions **2.** Write expected answers - What should the correct response be? **3.** Run evaluation - See how your current chatbot performs **4.** Fix failures - Update your chatbot's instructions or knowledge base **5.** Iterate - Add more test cases as you discover new scenarios ## Understanding Scores Each evaluation produces a score from 0% to 100%. The default passing threshold is **70%**. ### Score Ranges - **70%+ (Pass)** - The response meets quality standards - **Below 70% (Fail)** - The response has issues that should be reviewed The 70% per-test-case threshold is fixed. If you turn on **Block publish if this suite fails** (the publish gate), you can set a separate pass threshold for the whole suite. A medical chatbot might require 90%+, while a casual FAQ bot might be fine with 60%. ### What Different Scores Mean by Metric | Metric | High Score (70%+) | Low Score (<70%) | |--------|------------------|------------------| | **Factuality** | Answer matches expected content | Answer missing key facts or has different info | | **Faithfulness** | Answer is grounded in knowledge base | Answer contains hallucinated/invented info | | **Answer Relevancy** | Answer directly addresses the question | Answer is off-topic or tangential | | **Context Relevancy** | RAG retrieved relevant documents | RAG pulled irrelevant documents | > **Note:** **Expect Variation**: In practice, Answer Relevancy often scores highest (your AI probably answers what's asked), while Context Relevancy scores lowest (retrieval is hard!). Don't panic if your Context Relevancy is around 20-40%. Focus on it only if your chatbot is giving wrong answers despite having correct information in its knowledge base. ## What Happens Behind the Scenes When you run an evaluation, here's what happens: 1. Your chatbot receives the test question 2. It generates a response (just like it would for a real user) 3. A separate "judge" AI evaluates the response 4. The judge scores the response against the relevant criteria 5. You see the results and can act on failures This "LLM-as-Judge" approach is more sophisticated than simple string matching. It understands semantic meaning, handles paraphrasing, and provides reasoning for its scores. ## Next Steps Ready to start evaluating your chatbot? 1. **Navigate to your chatbot** in the Chipp dashboard 2. **Go to Insights > Moderation** and open the **Evals** tab to create your first evaluation suite 3. **Start with Factuality** and your 10 most important questions 4. **Run the evaluation** and review results 5. **Iterate** based on what you learn Remember: Evals aren't a one-time thing. As your chatbot evolves, your test suite should grow with it. The goal is to catch problems before your customers do. > **Note:** **Pro Tip**: Turn on **Run automatically on publish** for a suite so it runs automatically every time you publish, and turn on the publish gate to block a publish that scores below your threshold. This catches regressions before they reach production. ## Using with MCP You can create and run evaluations programmatically using the Chipp MCP Server, enabling automated testing workflows. ### Available Tools | Tool | Description | |------|-------------| | `list_evals` | List all evaluations for an app | | `create_eval` | Create an evaluation suite from test cases (optionally as a publish gate or run-on-publish suite) | | `run_eval` | Execute an evaluation (optionally filtered by test case tag) | | `list_eval_results` | List past runs of an evaluation | | `get_eval_result` | Get detailed results from a run | | `update_eval` | Modify test cases | | `delete_eval` | Remove an evaluation | ### Example Prompts ``` "Create an evaluation for my FAQ bot with 10 test cases from our pricing page" "Run the 'Quality Check' evaluation and show results" "List all evaluations for app 123" "Show details of the last evaluation run" ``` ### Workflow: Automated Quality Testing ``` You: Create an evaluation from my best-rated conversation yesterday AI: [Calls search_conversations to find it] [Calls create_eval with test_cases built from that conversation] Created evaluation "FAQ Quality Test" with 8 test cases. You: Run it AI: [Calls run_eval, then get_eval_result] ┌────────────────────────────────────────────────────────┐ │ FAQ Quality Test Results │ ├────────────────────────────────────────────────────────┤ │ Overall: PASSED (7/8 tests) │ │ Pass Rate: ████████░░ 87.5% │ │ │ │ ✓ Test 1: Password reset [PASS] 92% │ │ ✓ Test 2: Business hours [PASS] 88% │ │ ✗ Test 7: Complex billing [FAIL] 45% │ └────────────────────────────────────────────────────────┘ ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- ============================================================ SECTION: Knowledge & Memory ============================================================ # How Knowledge Sources Work Learn how your documents become searchable AI knowledge through embeddings and semantic search --- When you upload a document to your Chipp app, something powerful happens behind the scenes. Your files get transformed into a format that AI can search and understand semantically, not just by keywords, but by meaning. This guide explains how it works in plain terms. ## The Big Picture Here's what happens when you add a knowledge source: 1. **You upload a file** (PDF, document, spreadsheet, URL, etc.) 2. **We extract the text** from your file 3. **We split it into chunks** (smaller, manageable pieces) 4. **We create embeddings** (numerical representations of meaning) 5. **We store everything** in a searchable database 6. **Your AI gets a search tool.** When it decides a question needs your content, it searches the knowledge base and reads the most relevant chunks before answering Let's break down each step. ## Step 1: Text Extraction Different file types need different handling. We support: | File Type | What We Extract | |-----------|----------------| | **PDFs** | Text, tables, and content from complex layouts | | **Word Documents** | Formatted text and structure | | **Excel/CSV** | Tabular data converted to readable text | | **Web URLs** | Page content, cleaned of navigation and ads | | **YouTube Videos** | Transcripts and captions | | **Audio** | Spoken content, transcribed to text | | **Plain Text/Markdown/JSON** | Direct content | The goal is to get clean, readable text regardless of the original format. ## Step 2: Chunking AI models have limits on how much text they can process at once. Plus, when answering a question, you don't need an entire 50-page document, you need the relevant paragraph. **Chunking** splits your text into smaller pieces (typically a few pages worth each). We try to split at natural boundaries, between paragraphs or sections, so each chunk contains a complete thought. **Example:** A 20-page PDF might become 15-20 chunks, each containing related content that can stand on its own. ## Step 3: Creating Embeddings This is where the magic happens. ### What's an Embedding? An embedding is a list of numbers that represents the *meaning* of text. Think of it as coordinates in a giant map of concepts. **Simple analogy:** Imagine a map where: - "Dog" and "puppy" are placed close together (similar meaning) - "Dog" and "cat" are somewhat close (both pets) - "Dog" and "refrigerator" are far apart (unrelated concepts) Embeddings work the same way, but in thousands of dimensions instead of two. Text with similar meaning gets similar numbers. ### Why This Matters Traditional search looks for exact keyword matches. If your document says "automobile" but someone searches "car," traditional search might miss it. **Semantic search** using embeddings understands that "automobile" and "car" mean the same thing. It finds relevant content based on meaning, not just matching words. ### The Numbers Each chunk of text becomes a vector of ~3,000 numbers. These numbers encode: - What the text is about - The context and tone - Relationships to other concepts You don't need to understand the math, just know that similar content produces similar numbers, which makes searching incredibly powerful. ## Step 4: Storage We store both: - **The original text chunks** (so we can show them to the AI) - **The embeddings** (so we can search by meaning) This lives in a specialized vector database optimized for finding similar embeddings quickly. ## Step 5: Retrieval (Search as a Tool) Retrieval works as a **tool the AI calls**, not as an automatic step bolted onto every message. When your app has knowledge sources, its AI is given a `searchKnowledge` tool and told your knowledge base exists. Then, for each message, the AI decides whether it needs your content: ### 1. The AI Decides to Search "Hi!" doesn't need a knowledge lookup; "What's your refund policy?" does. When the question calls for your content, the AI calls the search tool with a query it writes itself. For complex questions it can search **multiple times with refined queries**, the way a person would try a second search after skimming the first results. ### 2. Hybrid Search Each search combines two strategies at once: **semantic search** (comparing the query's embedding against your chunk embeddings, so "car" finds "automobile") and **keyword search** (classic full-text matching, so exact names, part numbers, and rare terms aren't missed). By default the blend weighs meaning at 70% and keywords at 30%. ### 3. Relevance Scoring Each chunk gets a combined score. Chunks below the relevance threshold are dropped; the top results (up to your configured chunk limit) are returned. ### 4. The AI Reads the Results The search results come back to the AI as tool output: the matching chunks with their source documents. If the results don't answer the question, it can search again with a different query. ### 5. AI Response The AI answers grounded in what it actually found in your content, not just its general training data, and it knows which document each passage came from. **Why tool-based retrieval is better than searching on every message:** no wasted searches (and tokens) on messages that don't need your content, the AI writes better search queries than raw user messages ("it broke again" becomes a search for the product discussed earlier), and it can iterate when the first search misses. ## Why This Approach Works ### Semantic Understanding Users don't need to know the exact words in your documents. Ask about "pricing" and find content about "costs," "fees," or "rates." ### Accuracy By giving the AI specific, relevant content, answers are grounded in your actual information rather than generic responses. ### Scalability Whether you have 10 documents or 10,000, the search remains fast because embeddings can be compared efficiently. ### Relevance Instead of dumping entire documents into the AI (which would exceed limits and include irrelevant content), we surface just the pieces that matter. ## Document Boosting: Smarter Retrieval for Large Knowledge Bases When you have dozens or hundreds of knowledge sources, finding the right information becomes more challenging. A simple chunk-by-chunk search might return text that *sounds* relevant but comes from the wrong document entirely. This is where **document boosting** comes in. ### The Problem with Pure Chunk Search Imagine you have 50 documents uploaded: - Employee Handbook - API Documentation - Password Reset Guide - System Administration Manual - ...and 46 more A user asks: "How do I reset my password?" Pure chunk search might find: 1. "Reset API tokens in the developer console" (API docs) 2. "Reset your password in account settings" (Password Guide) 3. "Reset deployment configuration" (Admin Manual) The first result has high text similarity to "reset" but comes from the wrong context entirely. The user wanted account passwords, not API tokens. ### How Document Boosting Solves This We use a two-tier approach: **Tier 1: Document-Level Understanding** When you upload a document, we also generate an AI summary of the entire document and create an embedding for it. This captures what the document is *about* at a high level. For example: - Employee Handbook → "Company policies covering PTO, benefits, conduct..." - API Documentation → "Technical reference for developer integrations..." - Password Reset Guide → "Instructions for resetting user account passwords..." **Tier 2: Combined Scoring** When document boosting is enabled and the AI runs a search, we: 1. First find which *documents* are most relevant to the query 2. Then search for chunks, but **boost chunks from relevant documents** For "How do I reset my password?": - Password Reset Guide gets a high document relevance score (0.92) - API Documentation gets a low score (0.45) A chunk from the Password Guide with slightly lower text similarity (0.78) now outranks a chunk from API docs with higher text similarity (0.85), because it comes from the right context. ### Why Document Summaries Matter Document summaries serve as a "table of contents" for your entire knowledge base. They help the system understand: - What each document is about - Which documents are relevant to a query - How to prioritize chunks from contextually appropriate sources This is especially powerful when you have: - **Many similar documents** (multiple policy manuals, product guides) - **Overlapping terminology** (technical terms used in different contexts) - **Large knowledge bases** (hundreds of documents with thousands of chunks) ### The Result Document boosting delivers more accurate answers by understanding context at both the document and chunk level. Users get responses from the right source, not just text that happens to contain similar words. ## Real-World Example **Scenario:** You've uploaded your company's 50-page employee handbook. **User asks:** "How many vacation days do I get?" **What happens:** 1. The AI decides this question needs your content and calls its search tool 2. The search runs against your handbook chunks (meaning + keywords combined) 3. Finds the chunk about PTO policy (high score) 4. Also finds related chunks about holiday schedule (moderate score) 5. The AI reads the results 6. AI responds: "According to the employee handbook, full-time employees receive 15 vacation days per year, plus 10 company holidays..." The AI didn't have to read all 50 pages, just the relevant sections. ## Tips for Better Results ### 1. Quality Content The AI can only find what's in your documents. Make sure your knowledge sources contain the information users will ask about. ### 2. Clear Writing Well-organized, clearly written content produces better embeddings. If a human would struggle to understand your document, the AI will too. ### 3. Comprehensive Coverage If users frequently ask questions you can't answer, consider adding more knowledge sources to cover those topics. ### 4. Keep Sources Updated Outdated documents lead to outdated answers. Regularly refresh your knowledge sources with current information. ## Supported File Types | Type | Extensions | Best For | |------|------------|----------| | Documents | PDF, DOCX, DOC | Manuals, guides, reports | | Spreadsheets | XLSX, XLS, CSV | Data tables, lists, structured info | | Text | TXT, MD, JSON | Simple content, FAQs | | Web | URLs | Online documentation, articles | | Media | YouTube links | Video transcripts, tutorials | | Audio | MP3, M4A, MP4, WAV, WEBM, OGG, FLAC | Recordings, meetings, podcasts | ## Using with MCP You can manage knowledge sources programmatically using the Chipp MCP Server, enabling bulk operations and automated workflows. ### Available Tools | Tool | Description | |------|-------------| | `list_knowledge_sources` | List all sources for an app with status | | `add_url_source` | Add URL (auto-detects YouTube, social media, web pages) | | `add_document_source` | Upload a document (base64 encoded) | | `get_knowledge_source` | Get details and processing status | | `delete_knowledge_source` | Remove a knowledge source | | `refresh_knowledge_source` | Re-crawl or re-process a source | ### Example Prompts ``` "Add https://docs.example.com to my FAQ app with crawl depth 2" "List all knowledge sources for app 123" "Add this YouTube video to my training bot" "Refresh all outdated knowledge sources" ``` ### Workflow: Bulk Knowledge Migration ``` You: List knowledge sources in my old FAQ app (ID 100) AI: [Calls list_knowledge_sources] Found 8 sources: - docs.example.com (URL, COMPLETED) - Product Manual.pdf (FILE, COMPLETED) - FAQ-2024.docx (FILE, COMPLETED) ... You: Add all the URLs to my new FAQ app (ID 200) AI: [Calls add_url_source for each URL] Added 5 URL sources to app 200. Processing will complete in a few minutes. ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- # Knowledge Retrieval Settings How your AI searches your knowledge base, and the settings that tune retrieval quality, cost, and coverage. --- When you add knowledge sources (documents, websites, etc.) to your Chipp app, your AI uses **Retrieval-Augmented Generation (RAG)** to find and use that content. This guide explains how retrieval actually works and which settings tune it. ## How Your AI Uses Your Documents ### Retrieval is a tool, not a reflex Your AI does **not** search the knowledge base on every message. Instead, when your app has knowledge sources, the AI is given a `searchKnowledge` tool and told the knowledge base exists. On each message it decides for itself whether the question needs your content: - "Hi, how are you?" gets answered directly. No search, no wasted tokens. - "What's your refund policy?" triggers a search with a query the AI writes itself. - A complex question can trigger **several searches with refined queries**, the way a person would try a second search after skimming the first results. This matters for three reasons: 1. **Cost**: simple messages don't pay the retrieval tax. 2. **Query quality**: the AI writes better search queries than raw user messages. "It's still broken" becomes a search for the actual product and error discussed earlier in the conversation. 3. **Iteration**: if the first search misses, the AI can reformulate and search again instead of answering badly. ### What is a "chunk"? When you upload a document, Chipp automatically breaks it into smaller pieces called **chunks** (typically a paragraph or a few paragraphs). Chunks let a search return the exact relevant section instead of a whole 50-page document. **Example:** A 50-page PDF might be split into 200 chunks. A search scores all 200 and returns only the top few. ### How each search works Every search is a **hybrid search** combining two strategies at once: 1. **Semantic search** (70% of the score by default): the query and your chunks are compared as embeddings, so "How do I cancel my subscription?" matches a chunk about "ending your membership" even with zero shared words. 2. **Keyword search** (30% by default): classic full-text matching, so exact product names, error codes, and rare terms are never lost to fuzzy matching. Chunks below the relevance threshold are dropped, and the top results (up to your chunk limit) are returned to the AI along with which document each one came from. ### Document boosting Every search also uses a third signal by default: **document boosting**. Each document gets an AI-generated summary and its own embedding; when a search runs, chunks from documents that are relevant *overall* get boosted above stray chunks that merely share some words with the query. **Example:** A user asks about "return policies." Plain search might rank a chunk from a random product page above your Returns & Refunds document. With document boosting, chunks from the Returns document win because the document itself is highly relevant. ## Settings You Can Change in the Builder ### Max chunks per query **Default: 5** | Range: 1 - 25 | **Brain → Knowledge** The maximum number of chunks each search returns to the AI. | Value | Behavior | | --- | --- | | **Fewer chunks (1-3)** | Focused answers, lower token usage, faster | | **Moderate (4-7)** | Balanced context (recommended) | | **More chunks (8-25)** | Comprehensive coverage, higher token usage | Use fewer chunks for FAQ-style apps where answers live in one place; use more when questions require synthesizing information scattered across documents. More chunks means more context per search, but also higher token usage on every knowledge-backed answer. This setting takes effect when you re-publish the app. ## Advanced Tuning The remaining retrieval parameters are deliberately kept out of the builder UI (they're easy to hurt yourself with), but every app has them. You can tune them in three places, and all three accept the same values with the same limits: | Parameter | Default | Range | What it does | | --- | --- | --- | --- | | `maxResults` | 5 | 1-25, whole number | Same as "Max chunks per query" above | | `minScore` | 0.15 | 0-1 | Relevance threshold: chunks scoring below it are dropped. Raise it if answers include loosely related content; lower it if the AI misses information you know is there | | `vectorWeight` | 0.7 | 0-1 | How much semantic (meaning) similarity counts in the hybrid score | | `textWeight` | 0.3 | 0-1 | How much keyword (full-text) matching counts | | `useDocumentBoosting` | on | on / off | Applies the document-level boost described above | | `documentWeight` | 0.3 | 0-1 | With boosting on, how strongly document-level relevance re-ranks chunks | Each write changes only the parameters you send; the others keep their values. A value outside its range, or a misspelled name, is refused with an error, never silently ignored. To go back to a default, send the default value. Like max chunks, these take effect when you re-publish the app. **Alchemist copilot.** Ask in plain words: ``` "Raise my app's knowledge relevance threshold to 0.25 and retrieve 8 chunks per search." ``` **Chipp MCP Server.** Send the parameters as `settings.ragConfig` on [`update_app`](/docs/guides/mcp/tools-reference#update_app) or [`update_settings`](/docs/guides/mcp/tools-reference#update_settings): ```json { "app_id": "YOUR_APP_ID", "settings": { "ragConfig": { "minScore": 0.25, "maxResults": 8 } } } ``` **Builder API.** Send `ragConfig` in the body of `PATCH /api/applications/:appId`: ```json { "ragConfig": { "minScore": 0.25, "useDocumentBoosting": true } } ``` ## Troubleshooting ### AI doesn't find information that exists in my documents 1. Increase **Max chunks per query** to 8-10 2. Lower `minScore` toward 0.10 3. Make sure `useDocumentBoosting` has not been turned off 4. Check the knowledge source actually finished processing (its status should be COMPLETED) ### Responses include irrelevant information 1. Raise `minScore` to 0.25-0.35 2. Decrease **Max chunks per query** to 3-4 3. Review your documents for overlapping or contradictory content ### Token usage is too high 1. Reduce **Max chunks per query** to 3-4 2. Raise `minScore` to filter low-quality matches Remember that retrieval is tool-based, so messages that don't need knowledge don't incur retrieval cost at all; the levers above only affect knowledge-backed answers. ### AI gives conflicting information 1. Raise `minScore` to be more selective 2. Use a higher `documentWeight` for document boosting so answers stay within cohesive sources 3. Remove or update outdated documents ## Using with MCP You can manage knowledge sources and retrieval settings programmatically using the Chipp MCP Server. ### Available Tools | Tool | Description | |------|-------------| | `list_knowledge_sources` | List all sources with processing status | | `add_url_source` | Add URL with crawl depth options | | `add_document_source` | Upload documents (base64 encoded) | | `delete_knowledge_source` | Remove a knowledge source | | `refresh_knowledge_source` | Re-crawl or re-process a source | | `update_settings` | Modify app settings, including `settings.ragConfig` (max chunks and the advanced parameters above) | ### Example Prompts ``` "List all knowledge sources for my FAQ bot" "Add https://docs.example.com with crawl depth 3" "Refresh the outdated product manual" "Update my app to retrieve 10 chunks instead of 5" "Set my app's minimum relevance score to 0.3" ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. --- # User Memory Let your AI remember facts about users across conversations for personalized experiences. --- User Memory enables your AI to remember important facts about users across conversations. Instead of starting fresh every time, your AI can recall preferences, past interactions, and relevant details. ## What Is User Memory? User Memory automatically extracts and stores durable facts from conversations: | Memory Type | Examples | |-------------|----------| | **Fact** | "User's company is Acme Corp", "Works as a CTO" | | **Preference** | "Likes concise answers", "Prefers email over phone" | | **Instruction** | "Always reply in Spanish", "Don't use bullet points" | | **Context** | "Evaluating the enterprise plan", "Migrating off a legacy CRM" | Each memory is also stored in one of two layers: **Fact** (durable, kept indefinitely) or **Episodic** (decaying, for things that matter for a while). ## How It Works ``` User: "I'm the CTO at Acme Corp and we're evaluating your enterprise plan" ↓ [AI replies] ↓ [Memory extraction runs in the background] ↓ Memories stored: - Role: CTO - Company: Acme Corp - Interest: Enterprise plan ↓ [Next conversation] ↓ AI: "Welcome back! Last time we discussed enterprise pricing for Acme Corp..." ``` ## Enabling User Memory Memory is on by default for new apps. To review or change it: **1.** Open Memory Settings In your app's builder, open **Brain** and then the **Capabilities** tab. Find the **Memory** card. **2.** Auto-extract memories Toggle on **Auto-extract memories**. Your AI then learns preferences, facts, and context from conversations with each consumer. **3.** Recall memories in new conversations Toggle on **Recall memories in new conversations** to carry saved facts about a consumer into their later conversations. Turn this off for assessment, intake, or eligibility flows, where each conversation must be judged only on what the person says in it. Turning both switches off turns memory off completely. **4.** Consumer memory access (Optional) Toggle on **Consumer memory access** to let consumers view and delete their own memories from the chat menu. This is recommended for GDPR compliance. To steer what the AI remembers or ignores, put that guidance in your system prompt (see "Memory in Your System Prompt" below). ## Memory Categories ### Fact Personal facts about the user: - Name, job, and location - Company information - Dietary restrictions, family, pets ### Preference Likes, dislikes, and style: - Communication style (formal/casual) - Response length preference - Preferred formats (bullet points, paragraphs) ### Instruction How the user wants to be treated or how they want tasks done: - "Always answer in Spanish" - "Show the code before the explanation" ### Context Ongoing projects, goals, or situations: - Problems they're trying to solve - Products they're evaluating - Deadlines they mentioned ## Viewing Stored Memories Go to **Insights > Memory** in the builder and select a consumer to see: - All memories for that consumer - When each memory was created Filter the list by memory type (Preference, Fact, Instruction, Context, Experiential) or by layer (Episodic or Fact). ## Managing Memories ### Deleting Memories Remove memories that are: - Incorrect - Outdated - No longer relevant Click the delete icon on a memory and confirm. ### Clearing All Memories for a Consumer For compliance or cleanup, select the consumer in **Insights > Memory** and click **Clear all**. ## Best Practices ### What to Remember **Do remember:** - Professional context (company, role, industry) - Stated preferences - Key topics discussed - Problems they're solving **Don't remember:** - Sensitive personal information - Temporary states ("having a bad day") - Information they asked you to forget - Confidential business data without consent ### Privacy Considerations > **Warning:** Always inform users that your AI has memory capabilities. Consider adding to your system prompt: > > "I can remember relevant details from our conversations to provide better assistance. Let me know if you'd prefer I not remember something." ### Memory in Your System Prompt Help your AI use memories effectively: ``` You have access to memories about this user from past conversations. Use these to: - Personalize greetings and responses - Avoid asking questions they've already answered - Reference their specific context Don't: - Mention that you "remember" things in a creepy way - Assume memories are 100% accurate - Reference memories if they seem outdated ``` ## How Memory Extraction Works Memory extraction happens automatically, in the background, after each AI reply: 1. **Turn completes**: The AI finishes a reply (stopped or aborted replies are skipped) 2. **AI analysis**: A Claude Haiku model reads the exchange for memorable facts 3. **Structured extraction**: Facts are given a type (fact, preference, instruction, context) and a layer (durable fact or decaying episodic) 4. **Storage**: Memories are stored against the consumer Extraction is skipped for apps with Zero Data Retention turned on. ## Use Cases ### Customer Support Remember: - Product version they're using - Past issues they've reported - Preferred contact method - Technical expertise level ### Sales Conversations Remember: - Company size and industry - Budget discussions - Decision timeline - Stakeholders involved ### Personal Assistants Remember: - Work schedule preferences - Project names and contexts - Communication preferences - Recurring tasks ### Educational Apps Remember: - Learning progress - Topics mastered - Areas needing work - Preferred learning style ## Troubleshooting ### Memories Not Being Extracted 1. Verify **Auto-extract memories** is on in the Memory card 2. Check that Zero Data Retention is off for the app 3. Allow a few moments after a reply for extraction to finish 4. Verify the user is identified (not anonymous) ### Incorrect Memories 1. Delete incorrect memories 2. Add guidance to your system prompt about what to remember and what to ignore ### Too Many Memories 1. Add system prompt guidance to prioritize durable facts 2. Periodically clean up outdated memories ## Limitations Current limitations to be aware of: - **Extraction delay**: Memories from a reply are written in the background, so they may not be usable in the very next message - **Anonymous users**: Memories need an identified consumer - **Token limits**: Very long conversations may be truncated for extraction ## Using with MCP You can access user memories programmatically using the Chipp MCP Server. ### Available Tools | Tool | Description | |------|-------------| | `get_user_memories` | Retrieve memories stored for a specific consumer (`app_id`, `consumer_id`, optional type filter and limit) | ### Example Prompts ``` "Show me the memories my support bot has for consumer 8f2c..." "What facts has my app learned about this user?" "List only the instruction memories for this consumer" ``` ### Workflow: Reviewing User Insights ``` You: Show me the memories my sales bot has for john@acme.com AI: [Looks up the consumer, then calls get_user_memories] Found 6 memories: - fact: CTO at Acme Corp, 500+ employees - context: Evaluating the enterprise plan, budget approved - preference: Prefers short, direct answers ... ``` > **Note:** MCP server access requires a Builder plan or higher. See the [MCP Setup Guide](/docs/guides/mcp/setup) to get started. > **Note:** **Individual vs. group memory.** User Memory stores facts about a single user -- preferences, past interactions, and extracted insights. [Circles](/docs/guides/circles) complement this with shared group memory: a persistent context space that multiple users and AI agents read and write together. Use both for rich, personalized, and collaborative AI experiences. --- # Consumer Brain Persistent file storage for consumers that works across chat sessions and apps in your workspace. --- Consumer Brain gives your users a persistent file storage space that lives across chat sessions. Files generated during conversations, uploaded documents, and data outputs are saved automatically -- consumers can browse, organize, and reference them in future chats. > **Note:** Consumer Brain is available on every plan. It stores files for authenticated consumers only. ## What It Does | Feature | Description | |---------|-------------| | **Persistent storage** | Files survive across multiple chat sessions | | **File browser** | Slide-out **My Files** panel with search, sort, and type filters | | **Inline preview** | View images, PDFs, CSV, JSON, and text files without downloading | | **Attach to chat** | Reference stored files in new conversations | | **Auto-save** | Files generated by code execution are saved automatically | | **Cross-app access** | Authenticated users see files from other apps in your workspace | ## Enabling Consumer Brain **1.** Enable Persistent Storage Go to your app's **Capabilities** tab (under Brain) → **Code Execution** card. Toggle on **Persistent file storage**. **2.** Configure Retention (Optional) With persistent storage on, two more fields appear under the toggle. Set **File retention days** to delete files your AI generated (code outputs, downloaded pages) after that many days. Files a user uploads are never deleted by retention. Default is 0 (keep forever). The cleanup runs every hour, so a file can outlive its cutoff by up to an hour. **3.** Set Storage Limits (Optional) Set **Max storage per consumer** (in MB) to cap how much each user can store in this app. When a user is at the cap, new uploads to **My Files** are refused with a "Storage quota exceeded" message. Files your AI generates during a chat are still saved. Default is 0 (unlimited). ## How Consumers Use It ### File Browser Consumers open **My Files** from the chat menu to see their stored files in a slide-out panel. They can: - Browse files with search and sort options - Upload files directly into storage - Rename and delete files - Preview files inline (images, PDFs, CSV, JSON, text) - Attach a file to the chat with the **Attach to chat** action, or type `@` in the chat input to pick a stored file ### Automatic File Saving When your AI generates files during a conversation (charts, reports, code outputs), they're automatically saved to the consumer's persistent storage if enabled. The consumer doesn't need to manually download and re-upload. ### Cross-App File Sharing When consumers authenticate across multiple apps in your workspace, they can see files from sibling apps: - Cross-app files show with a badge indicating which app created them - Cross-app files are **read-only** (rename and delete only available on the original app) - Fact-based memories from other apps automatically augment the system prompt #### Controlling Cross-App Sharing Three switches control this sharing, and all of them must allow it: - **Workspace:** **Workspace Settings → Consumer sharing**, toggle **Share consumer context across apps**. Turns sharing on or off for every app in the workspace. - **HQ:** if the workspace has an HQ, **HQ Settings → Options → Consumer sharing**. Turning it off also stops sharing for the HQ's whole workspace. The switch only appears on an HQ that is linked to a workspace. - **Per app:** in the app's **Capabilities** tab, open the **Consumer Sharing** card and turn off **Share consumer context across apps** to keep that app's files to itself. All three are on by default. When an app is opted out, files from that app won't be visible to consumers using other apps, and that app sees no files from its siblings. The opt-out applies to everyone, including workspace members testing their own apps. ## Storage Billing Consumer Brain storage is metered as part of your plan's usage: - Storage is calculated in MB-months - Only applies to authenticated consumers ## Troubleshooting **Files not being saved?** - Verify **Persistent file storage** is toggled on in Capabilities → Code Execution - Uploads refused with "Storage quota exceeded"? The user is at **Max storage per consumer**. Raise the cap, or set it to 0 for unlimited **Cross-app files not showing?** - Verify **Consumer sharing** is on in **Workspace Settings** and, if the workspace has an HQ, in **HQ Settings → Options** - Check the app hasn't opted out of sharing - Consumer must be authenticated (signed in) on both apps **File preview not loading?** - Large files may take a moment to load - Signed URLs expire after 1 hour -- refresh the page if a download link has expired - Some binary formats may not support inline preview > **Note:** Consumer Brain is part of the persistent storage system. Files generated during [code execution](/docs/guides/maximize-chipp-capabilities) are automatically saved when enabled. > **Note:** **Sharing files across groups?** Consumers can share Consumer Brain files with a [Circle](/docs/guides/circles) -- a persistent, shared memory space where multiple members and connected AI agents all read the same context. Circles complement Consumer Brain: Brain is your personal storage; Circles are the team's shared notebook. --- # My Files: Your Document Library, Shared Across Your Assistants Upload a document once and every assistant you use can find it later, in any conversation. Share files with family or teammates through circles. --- When you upload a document in a chat, your assistant does more than read it once. It saves the document to **My Files**: your personal, permanent document library. In any later conversation, you can just refer to the document ("check my HOA rules", "what did my founder analysis say about vesting?") and the assistant will find it, read the relevant parts, and cite the file by name. No re-uploading. ## How it works 1. **Upload once.** Attach a document to any chat message while signed in. The original file is stored, its text is extracted, and a short summary is generated so your assistants know what it contains. 2. **Reference it any time.** In a new conversation, mention the document naturally. The assistant searches your library by name, summary, and content, then loads only the parts it needs, so a large library never slows down or crowds your conversations. 3. **Browse your library.** Open the menu in the top-right of any chat and choose **My Files**. You can search, filter, preview, download, rename, and delete documents, and see each document's processing status. Supported document types include PDF, Word, spreadsheets, CSV, Markdown, plain text, and images. Files up to 25MB are stored durably. ## One library across all your assistants If you use several assistants from the same builder (for example, a set of apps in one workspace or launched from one HQ home screen), they share your library. A document you upload in one assistant is readable by the others, labeled with where it came from, as long as you're signed in with the same email in each one. When an assistant uses a file you saved elsewhere, it will tell you which assistant it came from, so you always know the source. Builders control this sharing at three levels, and every level must allow it: **Workspace Settings → Consumer sharing** (whole workspace), **HQ Settings → Options → Consumer sharing** (an HQ linked to the workspace; off here also turns it off for the workspace), and per app (Brain → Capabilities → **Consumer Sharing**, turn off **Share consumer context across apps**) if an app should keep its files private to itself. All three are on by default. ## Sharing files with other people: circles Circles let you share files with people you choose: your spouse, your family, a small team. Each person keeps their own account and their own assistants, and shared files travel across. 1. **Create a circle** from **My Circles** in the chat menu, and invite members by email. They get an email invitation and accept from any of their own Chipp assistants. 2. **Share a file** from My Files: open the share action on any document and pick a circle. Every other member gets an email letting them know what you shared and who shared it. You can also just **ask your assistant** ("share the market research with my family circle"), or turn on **Auto-share new files** in the circle's panel to share everything you save automatically (auto-shares skip the per-file email). 3. **They can just ask.** Members' assistants can now find and read the shared file in conversation, always attributed ("shared by Hunter in your Family circle"). Members can also browse and download circle files from My Circles. Only the person who shared a file (or the circle owner) can remove it from the circle. Leaving a circle, or being removed by its owner, removes your access to its files. The owner removes a member (or cancels a pending invite) from the member list in the circle's panel. Read the full [circles guide](/docs/guides/circles) for invitations, shared memory, auto-share details, and privacy controls. ## Privacy notes - Your library is yours. Assistants can only read files belonging to your signed-in identity, plus files explicitly shared with you through a circle. - Anonymous (not signed-in) chats don't build a library: sign in to keep documents. - Deleting a file removes it from your library and from any circles it was shared into. --- # Circles - Shared Files and Agent Memory Share files, memory, and context with family or teammates across every AI assistant you each use. Share a document once (manually, by asking your assistant, or automatically) and every member's assistants can read it. --- A Circle is a shared space for the people (and agents) you choose: your spouse, your family, a study group, a small team. Create a circle, invite members by email, and connect the AI apps that should have access. Members share three things: - **Files.** Any document a member shares (researched, generated, or uploaded) becomes readable by every other member and their assistants. - **Shared memory.** A living notes page that every member's connected assistants can read and update. - **An event log.** An append-only activity feed with a full audit trail of who wrote what, and when. Circles are anchored to email addresses, not to any single app. Join once and the circle works in every circle-enabled assistant you sign into with that email, even assistants from different builders. Your family doesn't need to use the same app you do: they just need to be members. Think of a Circle as a shared notebook that every person and agent in the group reads from and writes to. > **Note:** **For people and for agents.** Circles work two ways at once: the simplest way for people to share files and context across their AI apps, and a production-grade shared memory surface for Alchemist projects, Builder API clients, and autonomous agents via MCP tools. Everyone reads and writes the same store, so there is nothing to sync. > **Warning:** Circles require the builder to enable the feature in the app's capabilities. Consumers must have a verified email (OTP-confirmed) to create or join circles. ## How Shared Agent Memory Works ``` Consumer (owner) creates a Circle | |- Invites members by email | |- Connects App A and Alchemist Project B | App A agent appends: "Client meeting rescheduled to Friday" | v (same DB row, same circle) Project B reads memory → includes "Client meeting rescheduled to Friday" | Project B appends: "Sent updated proposal via email" | v App A next turn → sees both entries, no manual sync required ``` Circles use Postgres as the single source of truth. Appends are atomic (no lost updates under concurrent writes). A full event log preserves history even when the current memory text is replaced. Provenance on every mutation records which actor (consumer, application, Alchemist project) wrote it and when. ## Key Concepts ### Email-Anchored Identity Consumers are per-app, but circles are cross-app. All consumer identity is based on verified email -- not app-specific user IDs. A consumer's "Family Circle" works in any circle-enabled app where they provide the same verified email. ### Shared Memory Each Circle has a `memory` field: a free-form text store any authorized writer can append to or (with admin permission) replace. Memory flows into connected agents' system prompts automatically, bounded and sanitized. Think of it as the team's shared context document. ### Event Log Circles have a sequential event log (`consumer_circle_events`). Every mutation (append, replace, custom publish) writes an event in the same transaction. Apps poll new events via cursor -- each connected app tracks its own `afterSeq` cursor so it only processes events it hasn't seen yet. ### App and Agent Connections A Circle is not accessible to an app or agent by default. An owner explicitly grants a connection, chooses a permission tier, and can revoke it at any time. No connection = no data, regardless of any other authentication. ### Permission Tiers | Tier | Can do | |------|--------| | **read** | Read memory, context, events, files, member list | | **write** | Everything in read + append memory + publish events | | **admin** | Everything in write + **replace** memory outright (destructive, requires explicit grant) | The default when a connection is first created is `read`. An owner must explicitly upgrade a connection to `write` or `admin`. ### Provenance Every mutation records: actor kind (`consumer`, `application`, `alchemist_project`, `service_agent`), actor identity (email or application/project ID), timestamp, and an optional idempotency key. This audit trail is preserved in `consumer_circle_events` even when the current `memory` text is overwritten by a later replace. --- ## For Consumers: Using Circles ### Creating a Circle **Verify Your Email.** Circles require a verified email. If you have not already, verify your email through the OTP flow. **Create the Circle.** Open the menu in the top-right of any chat, choose **My Circles**, and create a new circle with a name and optional description. **Invite Members.** Add members by email. They will receive an invite notification and can accept or decline. **Connect to Apps.** Once active, any member can connect the circle to any circle-enabled app they use. The connection is per-app and starts with read access. The owner can raise or revoke it later. ### Invitations - Only the circle **owner** can invite or remove members - Invited members see the circle in their pending invites list - Members can **accept** or **decline** an invitation - Declined invites can be re-sent by the owner - To remove a member, the owner opens the circle in the **Circles** panel and taps the remove button next to that member, then confirms. For a pending invite, the same button cancels the invite. The owner cannot remove themselves; to end the circle, delete it - A removed member loses access to the circle's memory, events, and files right away ### Roles | Role | Permissions | |------|------------| | **Owner** | Full control: invite/remove members, edit circle, delete circle, manage app connection grants | | **Member** | Read/write memory, connect/disconnect apps, view members, share/unshare files | Each member can have an optional **role description** (like "Budget manager" or "Trip planner") that is included in the AI's context, helping the AI understand each person's role in the group. ### Shared Memory The circle's memory field is a shared text document. Any member can read or append to it from a connected app. The AI automatically receives a bounded snapshot of this memory (up to 4,000 characters, plus the 10 most recent events) in its system prompt. ### File Sharing Any document in a member's [My Files library](/docs/guides/my-files-and-sharing) can be shared into a circle -- including files an assistant researched or generated for you, not just uploads. Shared files are accessible to every active member across all of their connected apps, always attributed ("shared by Hunter in your Family circle"). Your family doesn't need to use the same app you do: they just need to be members. There are three ways to share: 1. **From My Files.** Open **My Files** from the chat menu, hit the share action on any document, and pick a circle. Every other active member is notified by email. 2. **Just ask your assistant.** In any connected app, say "share the market research report with my family circle." The assistant finds the file in your library and shares it for you; members get the same email notification. 3. **Auto-share.** In the circle's detail panel, turn on **Auto-share new files**. From then on, every new file you save in a connected app (generated reports, researched documents, uploads) is shared to the circle automatically. Auto-shared files deliberately skip the per-file email so a busy research session doesn't flood anyone's inbox -- members see them in the circle's file list, and their assistants can read them immediately. What members can do with shared files: - **Browse and download** them from the Circles panel in any connected app (downloads use short-lived signed URLs) - **Ask their own assistant about them.** Members' assistants can list, read, and analyze circle files in conversation -- "summarize the retirement research Hunter shared" works from any member's app Rules and controls: - You can only share files you own (files in your own library, matched by your verified email) - Auto-share is personal and per-circle: it only affects files **you** create, only in apps **you** connected to that circle, and only files saved after you turned it on - Only the original sharer or the circle owner can unshare a file - Deleting a file from your library also removes it from any circles it was shared into; leaving a circle removes your access to its files File sharing events (`file_shared`, `file_unshared`) are recorded in the circle's event log; auto-shares carry an `autoShared: true` marker. ### Managing App and Agent Connections (Owner Only) As the circle owner you control which applications and AI projects can access your circle's data. Open the circle in the **Circles** panel. The **Connected apps** section is visible only to you: - **View connections** -- every app, project, or agent connected to the circle, its permission tier, when it connected, and whether it has been revoked (revoked rows stay in the list for your records) - **Change access** -- pick **Read**, **Write**, or **Admin** for each connection - **Revoke** -- immediate. The revoked connection loses all access on the very next call -- there is no TTL to wait out - **Restore** -- a revoked connection can be re-enabled with its previous tier, without creating a duplicate A connection is created when a member connects the circle to an app (the **Share with** toggle), and it starts at **Read**. To connect an Alchemist project or another app the panel does not list, use the owner API below with that application's ID. Revocation is the primary privacy control. If you no longer want an agent or project to see your circle's context, revoke it and the effect is immediate. ### Privacy - Your circle's memory, events, members, and files are only accessible to explicitly connected apps and projects with active (non-revoked) connection grants - A read-tier connection cannot write anything to your circle - Every write to your circle records the actor's identity and timestamp (provenance) on the circle's event log. The **Connected apps** section shows when each connection was made and revoked; the full provenance is readable through the events API - Circle content flowing into an AI system prompt is wrapped in explicit delimiters so the AI cannot be tricked into treating circle-authored text as system instructions (structural prompt-injection defense) --- ## For Builders: Enabling Circles in Your App To enable circles for your app, open the app's **Capabilities** tab (under Brain), find the **Circles** card, and turn on **Enable circles**. Circles are available on every plan. Once enabled, consumers with verified emails can create circles, invite members, and connect circles to your app. The circle context is automatically injected into the AI's system prompt for connected circles. ### What the AI Sees When a consumer with connected circles starts a chat, the AI receives bounded circle context including: - Circle name and description - Shared memory (capped at 4,000 characters -- truncated if longer, not raw dump) - Up to 10 most recent events (chronological) - Active member list with names, emails, roles, and role descriptions Memory and event content are wrapped in `<>` / `<>` delimiters in the actual prompt -- your system prompt's instructions take precedence over anything a circle member might write in the shared memory. This is structural, not keyword-based: even if someone writes the delimiter text inside the memory, it is escaped before injection. ### Owner-Facing Connection Endpoints Three routes are added to the consumer-authenticated circle surface (owner only) for managing non-consumer connections: | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/:appNameId/circles/:id/connections` | List all connections (including revoked) with permissions + audit provenance | | `PATCH` | `/:appNameId/circles/:id/connections/:appId` | Grant or update permission tier (`{ permissions, principalKind? }`) | | `POST` | `/:appNameId/circles/:id/connections/:appId/revoke` | Immediately revoke a connection | These are separate from the existing member-facing `POST /:id/connect` (creates a default read-only connection for the current app) and `DELETE /:id/connect` (removes the connection for the current app) -- both unchanged. --- ## For Alchemist Projects: Using Circles as Shared Memory An Alchemist project's own agent application can be granted access to a Circle by the circle's owner. Once connected, the project's agents can read and write Circle memory using standard MCP tools -- the same API surface any other connected app uses, with no separate Alchemist-only memory store. ### Setup 1. **The circle owner connects your project**: In the owner's app, under circle settings, the owner grants your Alchemist project's agent application a connection with the desired permission tier. Your project needs to have its agent application provisioned (automatic for most Alchemist Cloud projects). 2. **Your project discovers available circles**: Use the `list_circles` MCP tool to see which circles your project currently has access to. 3. **Read and write context**: Use `get_circle_context` for bounded, prompt-safe context retrieval, `append_circle_memory` to add context, and `read_circle_events` to poll for new events. ### MCP Tools Available to Alchemist Projects | Tool | Permission | Description | |------|-----------|-------------| | `list_circles` | read+ | List circles this project has access to | | `get_circle` | read+ | Circle metadata and active member list | | `get_circle_context` | read+ | Bounded, prompt-safe context (memory + recent events + members) | | `append_circle_memory` | write+ | Atomically append to shared memory | | `replace_circle_memory` | admin | Replace memory outright (CAS-guarded, admin only) | | `publish_circle_event` | write+ | Publish an explicit event to the event log | | `read_circle_events` | read+ | Cursor-first read of the event log | | `list_circle_files` | read+ | List files shared in the circle | See the [Circles Builder API & MCP Reference](/docs/builder-api/circles) for full request/response examples, concurrency semantics, and error codes. ### Cross-Agent Example ``` Alchemist Project A (research agent): - Discovers "Acme Project" circle via list_circles - Reads shared context via get_circle_context - Appends findings: "Competitor analysis complete. Key risk: pricing gap." - Uses idempotency_key: "research-complete-2026-07" to make the write safe to retry Chipp App B (client-facing agent, same circle): - Consumer asks: "What's the latest on the Acme project?" - System prompt receives bounded circle context including the research finding - Responds with up-to-date context, no manual sync required Consumer (owner): - Visits circle settings to inspect connection audit log - Sees: "2026-07-28 14:32 -- alchemist_project (Project A) appended memory" - Can revoke Project A's access at any time ``` --- ## API Reference ### Consumer-Authenticated Routes All circle endpoints for consumers are mounted at `/:appNameId/circles/` and require `consumerAuthMiddleware` + verified email. #### Circle CRUD | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/circles` | List your circles + pending invites | | `POST` | `/circles` | Create a new circle | | `GET` | `/circles/:id` | Circle detail + member list | | `PATCH` | `/circles/:id` | Update name/description (owner only) | | `DELETE` | `/circles/:id` | Delete circle (owner only) | #### Membership | Method | Endpoint | Description | |--------|----------|-------------| | `POST` | `/circles/:id/invite` | Invite a member by email (owner only) | | `POST` | `/circles/:id/accept` | Accept a pending invite | | `POST` | `/circles/:id/decline` | Decline a pending invite | | `DELETE` | `/circles/:id/members/:email` | Remove a member (owner only) | | `PATCH` | `/circles/:id/members/me` | Update your own member settings (`{ autoShareFiles }`) | #### Memory | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/circles/:id/memory` | Read the circle's shared memory | | `PUT` | `/circles/:id/memory` | Write or append to memory (`mode: replace` or `append`) | #### Events | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/circles/:id/events` | Read events (cursor-based) | Query parameters: `after_seq` (cursor), `limit` (max 100), `event_type` (filter). #### App Connections (Owner Only -- Connection Grants) | Method | Endpoint | Description | |--------|----------|-------------| | `POST` | `/circles/:id/connect` | Connect circle to the current app (member action) | | `DELETE` | `/circles/:id/connect` | Disconnect the current app (member action) | | `GET` | `/circles/:id/connections` | List all connections with permissions + audit (owner only) | | `PATCH` | `/circles/:id/connections/:appId` | Grant/update permission tier (owner only) | | `POST` | `/circles/:id/connections/:appId/revoke` | Immediately revoke a connection (owner only) | #### File Sharing | Method | Endpoint | Description | |--------|----------|-------------| | `GET` | `/circles/:id/files` | List shared files | | `POST` | `/circles/:id/files/:fileId` | Share a file to the circle | | `DELETE` | `/circles/:id/files/:fileId` | Unshare a file | | `GET` | `/circles/:id/files/:fileId/url` | Get a signed download URL | ### Non-Consumer (Builder API) Routes For Alchemist projects, third-party applications, and service agents, see the [Circles Builder API & MCP Reference](/docs/builder-api/circles). The Builder API surface uses a separate authentication path (Bearer API key + circle-scoped grant) and never impersonates a consumer email. --- ## Use Cases | Use Case | Who writes | Who reads | Example | |----------|-----------|----------|---------| | **Cross-agent research** | Alchemist research project | Chipp consumer-facing agent | Research agent appends findings; chat agent answers "what did we learn?" with up-to-date context | | **Family planning** | Any member via connected app | All members' agents | One member adds "Dad's birthday is March 15"; gift recommendation app for any member has that context | | **Team collaboration** | Multiple Alchemist projects | Shared client-facing agent | Marketing team's research project and copywriting project share a campaign brief circle | | **Customer handoff** | CRM integration (write grant) | Support agent (read grant) | CRM writes updated customer notes; support agent reads them on the next conversation | | **Audit trail** | Any writer | Owner reviewing provenance | Owner inspects event log to see exactly which agent appended what, and when | --- ## Safety and Limits ### Bounded Context Retrieval Circle content injected into LLM prompts is deliberately bounded: - **Memory**: capped at 4,000 characters by default (configurable up to 20,000 via API). Truncated with a `[truncated]` notice if longer - **Recent events**: last 10 events by default (configurable up to 50) - **Event payload**: an explicit event's `payload` may be at most 4,000 characters, measured as its JSON text. A larger payload is rejected (the Builder API returns `422 content_too_large`, the MCP tool returns a `content_too_large` tool error), never truncated. Memory appends and replaces record a preview of at most 4,000 characters in their audit event The bounded context endpoint (`GET /:circleId/context` via Builder API or `get_circle_context` via MCP) is what agents should use for prompt injection. The raw memory endpoint returns the full untruncated field. ### Prompt-Injection Defense Circle memory and event content are wrapped with explicit delimiters before injection into any LLM system prompt: ``` <> ...circle-authored text... <> ``` If the memory itself contains these delimiter strings, they are escaped before wrapping -- so a malicious circle member cannot forge the delimiter and break out of the untrusted content zone. This is a structural defense, not keyword-based classification. ### Concurrency Safety Concurrent writes to circle memory are safe by design: - **Append** is a single atomic SQL `UPDATE ... SET memory = memory || content`. No read-modify-write race. Two concurrent appends both persist -- neither is lost - **Replace** uses Compare-And-Swap: pass `expected_version` to gate the write on the current version. A stale version returns `409 version_conflict` with the actual current version instead of silently clobbering a concurrent writer - **Idempotency**: pass an `idempotency_key` on any write to make a retried call a safe no-op. The second call with the same key returns the original result without re-applying the write --- ## Troubleshooting **"Circles are not enabled for this app" (403)?** - The builder has not enabled circles in the app capabilities - Contact the app creator to request the feature **"Verified email required" (401)?** - You must verify your email through the OTP flow before using circles - Check your email for the verification code after signing up **Cannot invite members?** - Only the circle owner can invite or remove members - Verify the email address is correctly formatted **Circle not showing in another app?** - You must connect the circle to each app separately - Verify the other app has circles enabled - Make sure you are using the same verified email in both apps **A member doesn't see a file you shared?** - Check they accepted their invitation (a pending member has no access yet) - They should look in the Circles panel of a connected app, or ask their assistant to list circle files **Auto-share didn't share a file?** - Auto-share only covers files saved AFTER you turned it on, and only in apps connected to that circle - Share older files manually from My Files (or ask your assistant to share them) **Alchemist project cannot see circle data?** - The circle owner must grant the project's agent application a connection first - The connection must not be revoked - The API key must have `circles:read` scope **409 version_conflict on replace?** - A concurrent writer updated the memory between your read and your replace - Re-read the current memory + version (`GET /:circleId/memory`), merge your changes, and retry with the new `expected_version` > **Note:** Circles pair well with [Consumer Brain](/docs/guides/consumer-brain) for persistent file sharing across sessions, and [User Memory](/docs/guides/user-memory) for individual per-user context that complements group memory. For programmatic access by applications and agents, see the [Circles Builder API & MCP Reference](/docs/builder-api/circles). --- # Enterprise Knowledge Base: Scoped KBs for Your Organization Create an organization- or workspace-wide knowledge base, link it to authorized agents, and validate retrieval with the health dashboard. --- Most Chipp knowledge sources belong to a single app. An **enterprise (scoped) knowledge base** is different: it is owned by one app but shared with other apps in the same workspace or the same organization, so every authorized agent draws from the same reviewed corpus instead of each builder re-uploading the same documents. This guide walks a new admin from an empty org to a validated, agent-consumable knowledge base. ## Who this is for An organization owner/admin or a workspace owner/editor who wants one knowledge base to back multiple agents (support bot, internal copilot, onboarding assistant, etc.) instead of duplicating uploads per app. ## The three sharing scopes Every knowledge source has a **sharing scope**, one of three values: | Scope | Who can use it | |-------|-----------------| | **Private** (default) | Only the app that created it. | | **Workspace** | Every app in the same workspace as the owning app. | | **Organization** | Every app in the same organization, across all workspaces. | Changing a source's scope is immediate and reversible: widening it (Private -> Workspace -> Organization) makes it visible to more apps; narrowing it (or deleting a link) removes access on the very next request from the app that lost it -- there is no caching lag and no grace period. A source keeps its own chunks and embeddings in one place; a shared source is never copied or duplicated into the apps that use it. ## Guided setup path Follow these five steps in order. Each one is done from **Settings**. ### 1. Create a scoped knowledge base - **Organization-wide KB**: org owners/admins go to **Settings > Organization > Knowledge Base** and create or promote a source to **Organization** scope. - **Workspace KB**: any workspace owner/editor with knowledge-base write access goes to **Settings > Workspace > Knowledge Base** and creates or promotes a source to **Workspace** scope. Both screens list every source currently visible at that scope and let you add a new one (a fresh upload/URL) or promote an existing source your app already owns. ### 2. Ingest content Add the content the same way you would for any Chipp knowledge source: upload files, add a URL, or connect a supported connector (see [Supported Source Types](#supported-source-types-and-connector-status) below). If you're migrating a large existing library rather than adding a handful of documents, use the [bulk migration workflow](#migrating-an-existing-library) instead of adding sources one at a time. ### 3. Link authorized agents Linking makes a shared source *available* to another app -- being in-scope isn't enough on its own, the target app still needs an explicit link (or the automatic self-access every owning app already has). From the app you want to consume the shared KB, open **Brain > Knowledge**, click **Add Knowledge Source**, and choose **Saved Sources** to attach any source your app is authorized to see at its current scope. Unlink the same way when an agent should no longer draw on that source -- access is revoked immediately. ### 4. Validate retrieval with citations Chat with the linked agent and ask it something the shared source actually covers. A correct answer should come back with a citation back to the source. If the agent can't find the answer, check that: - the source has finished ingesting (see the health dashboard, next step), and - the source is actually linked to that app (or in-scope with a live link). ### 5. Check the health dashboard Go to **Settings > Workspace > KB Health** (use the **Organization** tab on that page for an org-wide view) to confirm the corpus is in good shape before relying on it in production. See [Health & Retrieval-Quality Metrics](#health--retrieval-quality-metrics) below for what each panel means. ## Supported source types and connector status Not every connector is at the same level of maturity. Chipp labels each one explicitly so you never assume support that isn't there: | Source type | Status | Notes | |-------------|--------|-------| | File upload (PDF, Word, Excel/CSV, text/Markdown, JSON) | **Supported** | Built-in ingestion pipeline; no external auth required. | | URL / web page | **Supported** | Built-in crawl-and-refresh pipeline with change detection. | | GitHub codebase | **Supported** | The most mature connector -- full sync lifecycle including incremental updates and deletions. | | Google Drive | **Supported** | OAuth-based sync with incremental updates. | | Microsoft OneDrive | **Supported** | OAuth-based sync with incremental updates. | | Citrix ShareFile | **Supported** | OAuth-based sync with incremental updates. | | Dropbox | **Supported** | OAuth-based sync with incremental updates. | | Box | **Supported** | OAuth-based sync with incremental updates. | | Slack, Jira, Confluence | **Unsupported as knowledge sources** | There is no Slack, Jira, or Confluence option in the knowledge source picker today. These are available as agent integrations (tools the agent calls live), not as synced knowledge sources. | | Notion | **Unsupported** | No working sync path exists in Chipp today. The Notion tile in the source picker only shows a roadmap notice. | **Unsupported today**: Notion, Slack, Jira, and Confluence (above) and any source not listed at all (for example, a proprietary internal system) have no built-in connector. Custom connectors can be built by Chipp engineering against the internal connector interface, but there is no self-serve path for an admin to add one. ## Permissions and governance Access is enforced at two layers, and both must agree before an app can read a shared source: 1. **Workspace role** -- creating, editing, deleting, reprocessing, refreshing, or changing the sharing scope of a knowledge source requires **write** access to the `knowledge_base` permission on the owning app's workspace. By default, workspace **owners** and **editors** have write access and **viewers** do not; an admin can further restrict an individual member's access below the role default. Organization owners/admins always have this access across every workspace in their org. 2. **Live scope + tenant check** -- every read (including agent/chat retrieval) and every mutation is re-validated against the source's *current* sharing scope and the requesting app's *current* workspace/organization at the moment of the request: - A **Private** source is only ever usable by its owning app. - A **Workspace**-scoped source requires the consuming app's workspace to match the owner's workspace, both non-null. - An **Organization**-scoped source requires the consuming app's organization to match the owner's organization, both non-null. - Any unrecognized or missing scope value is denied, never allowed. Because the check is live rather than cached, downgrading a source's scope (or deleting a link) takes effect immediately -- an app that loses access cannot keep reading stale data. On the retrieval side (what an agent, chat, or MCP client can read -- see [Agent and MCP access](#agent-and-mcp-access) below), a denied request is deliberately indistinguishable from one for a source that doesn't exist, so a caller can't probe for the existence of content they're not allowed to read. (The management screens, reachable only by a workspace member acting on apps they already belong to, may report a more specific reason when a shared source can't be linked.) ## Agent and MCP access An agent (in chat, or an external MCP client connected through Chipp's developer server) consumes a scoped knowledge base through the same authorized channel a person would use in the app's own Train tab -- it can only see sources the app is actually granted access to right now. When it answers from the knowledge base, it can: - **Discover** which knowledge sources it currently has access to. - **Search** across every source it's authorized for, ranked by relevance. - **Cite** the exact source and passage an answer came from, and re-fetch that passage later. - **Read** a full source document when it needs more context than a single search result provides. Every one of these capabilities re-checks authorization at the moment it runs. If a grant is revoked between a search and a follow-up read, the follow-up is denied the same way an outright-nonexistent source would be -- there is no way for the agent (or a user prompting it) to distinguish "revoked" from "never existed." ## Health & retrieval-quality metrics The Knowledge Base Health dashboard (Settings > KB Health, scoped to your workspace, or to your whole organization if you're an org owner/admin) reports only what it can measure directly from your corpus: - **Freshness**: flags a source as stale if it has never been refreshed, or its last successful refresh is more than 14 days old. - **Ingestion failures**: flags a source as failing if its current status is "failed," or it recorded a failed refresh attempt in the last 7 days. - **Embedding coverage**: the ratio of embedded rows to total rows, tracked separately for chunks and for document summaries -- this tells you how much of a source is actually searchable versus still processing. - **Usage (fan-out)**: how many other apps currently link to a given source. - **Retrieval quality**: recall/precision scored against a labeled set of test questions you supply, run live against the real retrieval pipeline. This is opt-in -- if you don't supply a labeled query set, the dashboard shows an explicit "no evaluation data" state rather than a fabricated score. Each metric on the dashboard states its own definition and time window so you never have to guess what a number means. Every stale or failing source links directly to a remediation action (refresh or reprocess) where one is available. ## Migrating an existing library If you're bringing over a large existing library rather than adding a handful of sources by hand, use the bulk migration intake instead of the UI's one-at-a-time flow. It takes a manifest (a JSON list of URLs and already-staged files), previews what it will do in a dry run with zero mutations, and is resumable -- a partially-completed run can pick up where it left off without re-ingesting anything already done. Sources created this way are bound to the sharing scope you specify (Private, Workspace, or Organization) and go through the exact same authorization chain as sources added one at a time in the UI. See `docs/runbooks/bulk-kb-import.md` in the engineering repo for the manifest format and command reference, or ask your Chipp contact to run a migration on your behalf. ## Limits and troubleshooting - **Retrieval quality scoring only runs when you supply a labeled query set.** There is no default or platform-provided benchmark; the dashboard will show "no evaluation data" until you provide one. - **Search results are ranked top-K, not a full corpus scan.** A single search returns a bounded, ranked set of results (up to 25 per page); it is not designed for exhaustive retrieval of every matching passage. - **An agent that "can't find" something in a linked source** is usually one of: the source hasn't finished ingesting yet (check Health), the link was removed or the scope was narrowed, or the content genuinely isn't a good semantic match for the question asked -- try a more specific question. - **A retrieval denial never tells you *why*.** By design, on the retrieval path (agents, chat, and MCP clients) "this doesn't exist" and "you're not authorized" look identical, so an answer can't be used to probe for content you aren't allowed to read. If something you expect to be shared isn't showing up, check the source's sharing scope and confirm the consuming app is linked (or shares the workspace/organization), rather than assuming it's broken. ## Should you build this yourself or use Chipp's enterprise KB? If you're deciding whether to build custom infrastructure for a shared, governed knowledge base versus using what Chipp already provides, here's what ships today: | Capability | Chipp Enterprise KB | |---|---| | Scoped sharing (private / workspace / org) without duplicating content | Built in | | Fail-closed authorization re-checked on every read and write, not just at link creation | Built in | | Health + retrieval-quality dashboard with defined metrics and remediation links | Built in | | File, URL, GitHub, and OAuth cloud-storage connectors (Drive, OneDrive, ShareFile, Dropbox, Box) | Built in | | Resumable, dry-run-first bulk migration for large existing libraries | Built in | | Agent/MCP evidence retrieval with citations, gated by the same live authorization | Built in | Building an equivalent system from scratch means re-implementing scoped authorization that fails closed under every edge case (stale links, revoked grants, cross-tenant probes), a retrieval pipeline with citation tracking, and connector sync logic with incremental updates and deletion handling -- all before you get to actually using the knowledge base for anything. This comparison covers capabilities only; it does not address cost, support terms, or compliance posture, which are commercial questions outside the scope of this guide. --- ============================================================ SECTION: Design & Experience ============================================================ # Style Studio Use AI to generate custom themes and CSS for your chatbot interface. --- Style Studio is a full-screen design environment inside the app builder where you can customize the look and feel of your chatbot's interface using AI or manual CSS. Describe what you want in plain English and the AI generates a complete theme -- colors, typography, bubble shapes, animations, and more. ## How It Works Style Studio pairs a live chat preview with the Alchemist AI assistant. You describe the visual style you want, and the AI generates CSS that targets over 50 custom properties controlling every visual aspect of the chat interface. ``` You: "Make it look like a premium fintech app with dark mode, sharp corners, and a monospace font" | AI generates CSS targeting: --chat-font-family, --chat-bubble-radius, --chat-user-bubble-bg, --chat-assistant-bubble-bg, --chat-input-bg, --chat-send-btn-bg, ... | Live preview updates instantly ``` The AI sees a **sprite sheet** of all chat UI elements (welcome screen, user messages, assistant messages with markdown, tool cards, web sources, image generation, voice, error states, typing indicators, input area, and standalone tools) so it understands exactly what it is styling. This visual context means the AI can make informed decisions about color contrast, spacing, and typography across every element type. ## Getting Started **1.** Open Style Studio Navigate to your app in the builder, open **Experience**, and click the **Style Studio** tab. **2.** Describe your style Open the Alchemist panel and describe the look you want. Be specific about colors, typography, mood, or reference a brand. Examples: - "Minimal and clean with lots of whitespace, soft grays, and Inter font" - "Bold and playful with rounded bubbles, bright gradients, and a comic book feel" - "Match our brand: navy blue (#1a237e), gold accents, serif headings" **3.** Iterate The Alchemist supports multi-turn conversation. Ask for changes: - "Make the user bubbles more rounded" - "Switch to a darker background" - "Add a subtle glow to the send button" Each iteration builds on the previous CSS, so changes are cumulative. **4.** Save Changes auto-save after 1.5 seconds of inactivity. The CSS, animation config, and welcome background preset are all persisted automatically. ## What You Can Customize Style Studio controls the entire chat interface through CSS custom properties. Here are the major categories: | Category | Properties | Examples | |----------|-----------|----------| | **Typography** | `--chat-font-family`, `--chat-font-size` | Google Fonts, system fonts, size scaling | | **User bubbles** | `--chat-user-bubble-bg`, `--chat-user-bubble-color`, radius, padding, border, shadow | Gradients, solid colors, rounded or sharp corners | | **Assistant bubbles** | `--chat-assistant-bubble-bg`, `--chat-assistant-bubble-color`, radius, padding, border, shadow | Independent styling from user bubbles | | **Input area** | `--chat-input-bg`, `--chat-input-color`, `--chat-input-radius`, `--chat-input-area-bg` | Footer background, input field styling | | **Send button** | `--chat-send-btn-bg`, `--chat-send-btn-color`, `--chat-send-btn-radius`, size, shadow | Circle, rounded square, custom colors | | **Code blocks** | `--chat-code-bg`, `--chat-code-color`, syntax highlighting variables | Dark/light code themes, custom syntax colors | | **Welcome screen** | Background preset selection | Retro grid, aurora, particles, gradient flow, mesh gradient | ## Animation Config The AI can also recommend streaming text animation settings alongside the CSS. These control how new text appears during AI responses: | Setting | Options | Description | |---------|---------|-------------| | **Type** | fade, blur, slideUp, slideDown | How tokens appear | | **Duration** | 50-500ms | Speed of the animation | | **Tokenize** | word, char | Animate by word or by character | Animation settings appear as a metadata badge in the Style Studio when the AI recommends them. They are saved to your app's capabilities automatically. ## Welcome Background Presets The AI can suggest a background animation for your chatbot's welcome screen. Available presets: - **Retro Grid** -- Perspective grid lines that recede into the distance - **Aurora** -- Soft, shifting aurora borealis gradients - **Particles** -- Floating particle field - **Gradient Flow** -- Smooth flowing color gradients - **Mesh Gradient** -- Organic mesh gradient blobs ## CSS Security and Scoping Custom CSS goes through two safety layers before it reaches the browser: ### Sanitization All CSS is sanitized to remove potentially dangerous patterns: - `@import` directives (prevents loading external stylesheets) - `javascript:` URLs, `expression()`, and `behavior:` (legacy XSS vectors) - Event handler attributes and script tags - Non-image data URIs (data:image/* is allowed for backgrounds) - External URLs not on the Google Fonts allowlist ### Scoping Every CSS rule is automatically prefixed with `[data-app-id=""]` so your custom styles only affect your chatbot. This means: - Your CSS cannot leak into the host page when embedded as a widget - Multiple chatbots on the same page cannot interfere with each other - `@keyframes` and `@font-face` declarations are left global (they need to be) - `@media` and `@supports` queries have their inner selectors scoped > **Note:** You never need to write the scoping selector yourself. Write CSS as if your rules are already inside the chat container, and the scoper handles the rest. ## Layout Archetypes The AI uses four layout archetypes when generating styles: 1. **Document-style** (the default) -- Styled user bubbles, full-width assistant messages with no bubble or border, reading-focused 2. **Conversational** -- Filled bubbles on both sides, iMessage-style 3. **Subtle Background** -- Styled user bubbles, with a faint tinted band (not a border) behind assistant messages 4. **Symmetric** -- Both sides get a similar bubble treatment, differentiated only by color The AI avoids outlined assistant bubbles next to filled user bubbles, since that combination reads as unpolished. The AI chooses the archetype based on keywords in your description and can switch between them on request. ## Google Fonts The AI has access to a curated list of Google Fonts and will include `@font-face` declarations in the generated CSS. Fonts are loaded from `fonts.googleapis.com` and `fonts.gstatic.com`, which are the only external domains allowed in custom CSS. > **Warning:** The AI avoids using display or decorative fonts (like Playfair Display or DM Serif Display) as the primary chat font. These fonts are designed for headings, not long-form reading, and cause readability issues in chat interfaces. ## Tips for Better Results 1. **Be specific about mood**: "Professional and trustworthy" gives better results than "make it look good" 2. **Reference brands**: "Style it like Linear" or "Apple-inspired minimal" gives the AI strong direction 3. **Provide hex codes**: If you have brand colors, include them directly 4. **Iterate incrementally**: Start with a broad direction, then refine details 5. **Ask about dark mode**: The AI can generate styles that work well in both light and dark modes ## How It Integrates Custom CSS from Style Studio is saved to your app's `customCss` field. When a consumer loads your chatbot: 1. The CSS is sanitized and scoped server-side 2. A `