This is the full developer documentation for Tanzanite # Tanzanite Documentation > Orchestrate autonomous AI agents — from the app, or from your own code. ## Two ways in [Section titled “Two ways in”](#two-ways-in) Using Tanzanite For people running the Tanzanite app. Create projects, chat with agents, build workflows, and ship apps. [Get started →](/using/overview/) Connecting to Tanzanite For developers and **autonomous agents**. Drive sessions over the SDK and REST API, stream events, and discover the platform via MCP. [Read the integration guide →](/connecting/overview/) ## For AI agents reading this site [Section titled “For AI agents reading this site”](#for-ai-agents-reading-this-site) This documentation is agent-readable. A condensed index of every page lives at [`/llms.txt`](/llms.txt), the full concatenated docs at [`/llms-full.txt`](/llms-full.txt), and machine-readable service descriptors are published under [`/.well-known/`](/.well-known/mcp.json) and [`/openapi.json`](/openapi.json). Every HTML page also has a `text/markdown` alternate — request a page with `Accept: text/markdown` to get clean Markdown. # Authentication > Authenticate to the Tanzanite API with an API key, and sign up programmatically so autonomous agents can onboard without a human. All programmatic access to Tanzanite uses an **API key**. ## API keys [Section titled “API keys”](#api-keys) Pass your key when constructing the client: ```typescript import { Tanzanite } from "@tanzanite/sdk"; const client = new Tanzanite({ apiKey: "tanzanite_your_key_here" }); ``` On raw HTTP requests, send the key as **either** header — Bearer or the `X-Tanzanite-Key` header: ```http Authorization: Bearer tanzanite_your_key_here ``` ```http X-Tanzanite-Key: tanzanite_your_key_here ``` Keys are scoped to your account and can be created and revoked from the app. Treat them as secrets — never embed a key in client-side code you ship to users. ## Programmatic signup (agent-friendly) [Section titled “Programmatic signup (agent-friendly)”](#programmatic-signup-agent-friendly) Autonomous agents can onboard without a human in the loop. The signup endpoint accepts a plain JSON body and returns a Firebase ID token and refresh token (plus the new user record). Errors come back as JSON: ```http POST /api/auth/signup Content-Type: application/json { "email": "agent@example.com", "password": "at-least-6-chars", "displayName": "My Agent" } ``` ```json { "user": { "uid": "...", "email": "agent@example.com", "emailVerified": false }, "idToken": "...", "refreshToken": "...", "expiresIn": "3600" } ``` `displayName` is optional. The marketing site also offers an interactive signup dialog, but it’s a JavaScript single-page app that posts to this same `POST /api/auth/signup` endpoint — there is no static HTML `
` that works without JavaScript. Agents that operate a browser can either drive that dialog or, more simply, call the endpoint directly as shown above. ## Errors [Section titled “Errors”](#errors) The SDK throws typed errors so you can branch on failure cleanly: | Error class | HTTP status | Meaning | | --------------------- | ----------- | ----------------------------- | | `AuthenticationError` | 401 | Invalid or missing API key | | `NotFoundError` | 404 | Resource not found | | `RateLimitError` | 429 | Rate limit exceeded | | `SessionError` | 400 | Session-specific error | | `TanzaniteError` | any | Base class for all API errors | ## Next steps [Section titled “Next steps”](#next-steps) * [SDK Quickstart](/connecting/sdk-quickstart/) — create your first session. * [REST API](/connecting/rest-api/) — call the API without the SDK. # Streaming Events > The event reference for Tanzanite agent sessions (real-time streaming is planned), plus listener patterns. A session produces a sequence of typed events. Every event has a `type` discriminator field. Streaming is not yet available Real-time delivery of these events over WebSocket is **planned but not yet available** in the SDK — `session.stream()` and `session.on(...)` will not connect today. Until streaming ships, follow a session by polling `session.getMessages()` and `session.getInfo()` (see [Sessions](/connecting/sessions/)). The reference below describes the event shapes the SDK stream will deliver once enabled. ## Listening (planned) [Section titled “Listening (planned)”](#listening-planned) ```typescript // Specific event type const unsub = session.on("token", (event) => { process.stdout.write(event.content); }); // All events session.onAny((event) => console.log(event.type, event)); // Manual control session.startStreaming(); session.stopStreaming(); // Async iterator (auto-connects, auto-disconnects) for await (const event of session.stream()) { // ... } ``` ## Event types [Section titled “Event types”](#event-types) | Type | Description | Key fields | | -------------------- | ----------------------- | -------------------------------------------- | | `token` | Streaming token | `content`, `accumulated` | | `message` | Complete message | `role`, `content`, `timestamp` | | `tool_call` | Tool invocation | `toolName`, `arguments`, `callId` | | `tool_result` | Tool execution result | `toolName`, `callId`, `success`, `output` | | `human_input_needed` | Agent needs human input | `inputId`, `question`, `category`, `choices` | | `status_change` | Session status changed | `previousStatus`, `newStatus` | | `cost_update` | Token/cost usage update | `totalCost`, `totalTokens` | | `subagent_spawned` | A subagent was created | `subagentId`, `scope`, `specialization` | | `subagent_complete` | A subagent finished | `subagentId`, `status`, `report` | | `complete` | Session completed | `report`, `cost` | | `error` | An error occurred | `message`, `code` | ## Handling subagents [Section titled “Handling subagents”](#handling-subagents) When an agent parallelizes work, you’ll see `subagent_spawned` and `subagent_complete` events alongside the main stream. Use `subagentId` to group a subagent’s tokens and tool calls in your UI. ## Next steps [Section titled “Next steps”](#next-steps) * [REST API](/connecting/rest-api/) — the underlying HTTP surface. # MCP & Agent Discovery > How autonomous agents discover Tanzanite and its capabilities — llms.txt, OpenAPI, MCP, and A2A agent cards under /.well-known/. Tanzanite publishes standard, machine-readable descriptors so autonomous agents can **discover** the platform, understand its capabilities, and act on it without a human writing integration code. ## Discovery files [Section titled “Discovery files”](#discovery-files) | File | Purpose | | ------------------------------------------------------ | -------------------------------------------------------- | | [`/llms.txt`](/llms.txt) | Condensed, link-rich index of the documentation for LLMs | | [`/llms-full.txt`](/llms-full.txt) | The full documentation concatenated into one document | | [`/openapi.json`](/openapi.json) | The REST API contract (OpenAPI) | | [`/.well-known/mcp.json`](/.well-known/mcp.json) | MCP server discovery for public integrations | | [`/.well-known/agents.json`](/.well-known/agents.json) | Agent discovery descriptor | | [`/.well-known/agent.json`](/.well-known/agent.json) | Google A2A agent card | ## Markdown content negotiation [Section titled “Markdown content negotiation”](#markdown-content-negotiation) Every documentation page has a clean Markdown twin. Request any page with an `Accept: text/markdown` header and you’ll receive Markdown instead of HTML: ```bash curl -H "Accept: text/markdown" https://docs.tanzanite.dev/connecting/overview/ ``` Each HTML page also links its alternate via ``, so crawlers can find the Markdown without guessing. ## MCP [Section titled “MCP”](#mcp) Tanzanite supports the Model Context Protocol so agents and MCP-aware clients can connect to it as a tool server. The descriptor at [`/.well-known/mcp.json`](/.well-known/mcp.json) advertises the server endpoint and metadata; point an MCP client at it to enumerate available tools. ## A2A (agent-to-agent) [Section titled “A2A (agent-to-agent)”](#a2a-agent-to-agent) For agent-to-agent interoperability, the A2A **agent card** at [`/.well-known/agent.json`](/.well-known/agent.json) describes Tanzanite as an agent another system can delegate work to. ## Next steps [Section titled “Next steps”](#next-steps) * Start building with the [SDK Quickstart](/connecting/sdk-quickstart/). # Connecting to Tanzanite > Integrate AI agents into your own application with the Tanzanite SDK, REST API, and MCP discovery — built for developers and autonomous agents. This section is for **developers** building on Tanzanite and for **autonomous agents** that drive Tanzanite programmatically. Tanzanite exposes a clean, type-safe surface for creating agent sessions, following their work, handling human-in-the-loop input, and controlling execution. ## Ways to connect [Section titled “Ways to connect”](#ways-to-connect) * **`@tanzanite/sdk`** — a lightweight, zero-dependency TypeScript SDK for Node.js 18+ and browsers. The fastest path. See the [SDK Quickstart](/connecting/sdk-quickstart/). * **REST API** — call the API directly if you’re not on JS/TS. See the [REST API](/connecting/rest-api/) and the machine-readable [`/openapi.json`](/openapi.json). * **MCP & discovery** — agents can discover Tanzanite and its capabilities through standard descriptors under `/.well-known/`. See [MCP & Agent Discovery](/connecting/mcp-and-discovery/). ## The shape of an integration [Section titled “The shape of an integration”](#the-shape-of-an-integration) 1. **Authenticate** with an API key (or programmatic signup). See [Authentication](/connecting/authentication/). 2. **Create a session** with a goal and optional context. See [Sessions](/connecting/sessions/). 3. **Follow the run** — poll for status and new messages as the agent works. Real-time event streaming is planned; see [Sessions](/connecting/sessions/) and [Streaming Events](/connecting/events/). 4. **Respond to human input** when the agent asks, and **control** the session (pause, resume, redirect, cancel). ## For autonomous agents [Section titled “For autonomous agents”](#for-autonomous-agents) If you are an AI agent reading this: a condensed map of the whole platform is at [`/llms.txt`](/llms.txt), the full docs at [`/llms-full.txt`](/llms-full.txt), the API contract at [`/openapi.json`](/openapi.json), and MCP server discovery at [`/.well-known/mcp.json`](/.well-known/mcp.json). Programmatic signup is documented under [Authentication](/connecting/authentication/). # REST API > Call the Tanzanite API directly over HTTP, without the SDK. Includes the low-level RestClient and the machine-readable OpenAPI spec. If you’re not on JavaScript/TypeScript, drive Tanzanite over plain HTTP. The SDK is a thin wrapper over this surface. ## Base URL and auth [Section titled “Base URL and auth”](#base-url-and-auth) ```plaintext https://api.tanzanite.dev ``` The public `/v1` surface is authenticated with your Tanzanite **API key**, sent as either header: ```http Authorization: Bearer tanzanite_your_key_here ``` ```http X-Tanzanite-Key: tanzanite_your_key_here ``` `/api/auth/signup` is the one unauthenticated endpoint. ## Machine-readable spec [Section titled “Machine-readable spec”](#machine-readable-spec) The full contract is published as OpenAPI at [`/openapi.json`](/openapi.json). Point your codegen, client, or agent at it rather than hand-copying endpoints — it is the source of truth. ## Core endpoints [Section titled “Core endpoints”](#core-endpoints) | Method | Path | Purpose | | ------ | ----------------------------------------- | -------------------------------------------------------------------------- | | `POST` | `/api/auth/signup` | Create an account (no API key needed) | | `POST` | `/v1/sessions` | Create a session — body `{ goal, context?, guardrails? }` | | `GET` | `/v1/sessions/{id}` | Get session status, cost, and rounds | | `POST` | `/v1/sessions/{id}/signal` | Control a session — `{ type: pause \| resume \| cancel \| redirect, ... }` | | `POST` | `/v1/sessions/{id}/human-input/{inputId}` | Respond to a human-input request | | `GET` | `/v1/sessions/{id}/messages` | List messages (`limit`, `after` cursor) | ### Control signals [Section titled “Control signals”](#control-signals) There is one control endpoint, `POST /v1/sessions/{id}/signal`, with a `type`: * `pause` — optional `reason`. * `resume` — optional `newBudget`; resuming a cost-limited session **requires** a `newBudget` greater than the current spend. * `redirect` — **requires** `message` (the new direction). * `cancel` — optional `reason`; also cancels active rounds and subagents. Note These paths mirror `apps/api/src/routes/sdk.ts`. If anything drifts, [`/openapi.json`](/openapi.json) is authoritative. ## Following a session [Section titled “Following a session”](#following-a-session) Real-time WebSocket streaming on the public `/v1` surface is **planned but not yet available**. Today, follow a running session by polling: * `GET /v1/sessions/{id}` — status, cost, and completion report. * `GET /v1/sessions/{id}/messages?after={lastRoundId}&limit=50` — new messages; advance the `after` cursor (the last `roundId` you saw) on each poll. A `status` of `complete`, `failed`, or `cancelled` is terminal. `waiting_human` means the agent is blocked on a human-input request — respond via `POST /v1/sessions/{id}/human-input/{inputId}`, then keep polling. ## Low-level client (SDK) [Section titled “Low-level client (SDK)”](#low-level-client-sdk) If you use the SDK but want raw requests, the `RestClient` is exported: ```typescript import { RestClient } from "@tanzanite/sdk"; const client = new RestClient({ baseUrl: "https://api.tanzanite.dev", apiKey: "tanzanite_your_key_here", }); const data = await client.get("/v1/sessions/sess_123"); ``` ## Next steps [Section titled “Next steps”](#next-steps) * [MCP & Agent Discovery](/connecting/mcp-and-discovery/) — let agents find you. # SDK Quickstart > Install @tanzanite/sdk, create a session, and follow its progress. The `@tanzanite/sdk` is a lightweight, **zero-dependency** TypeScript SDK. It works in browsers and Node.js 18+ (it uses native `fetch`). ## Install [Section titled “Install”](#install) ```bash npm install @tanzanite/sdk ``` ## Create a session and follow its progress [Section titled “Create a session and follow its progress”](#create-a-session-and-follow-its-progress) ```typescript import { Tanzanite } from "@tanzanite/sdk"; // Initialize the client with your API key const client = new Tanzanite({ apiKey: "tanzanite_your_key_here" }); // Create a session const session = await client.createSession({ goal: "Design a challenging game level", context: { projectId: "proj_1", sceneId: "scene_main" }, }); // Poll for new messages and status until the session finishes const TERMINAL = ["complete", "failed", "cancelled"]; let after: string | undefined; while (true) { const info = await session.getInfo(); const { messages } = await session.getMessages({ after, limit: 50 }); for (const msg of messages) { console.log(`[${msg.role}] ${msg.content}`); after = msg.roundId; // advance the cursor so we only fetch new messages } if (info.status === "waiting_human") { // The agent is blocked on a question — respond, then keep polling. // See Sessions → Human input for choice / free-text responses. } if (TERMINAL.includes(info.status)) { console.log("Done:", info.status, info.completionReport ?? ""); break; } await new Promise((r) => setTimeout(r, 2000)); // poll every 2s } ``` Real-time streaming is not yet available The SDK’s WebSocket streaming methods (`session.stream()`, `session.on(...)`, `session.startStreaming()`) are on the roadmap but **not yet wired to a server endpoint**, so they will not connect. Until streaming ships, follow a session by polling `session.getInfo()` and `session.getMessages()` as shown above. The event types in [Streaming Events](/connecting/events/) describe the planned stream. ## Configuration [Section titled “Configuration”](#configuration) | Option | Type | Default | Description | | --------- | -------- | --------------------------- | -------------------------------------------- | | `apiKey` | `string` | **(required)** | Your Tanzanite API key | | `baseUrl` | `string` | `https://api.tanzanite.dev` | API base URL | | `wsUrl` | `string` | *(derived from `baseUrl`)* | Reserved for streaming *(not yet available)* | | `timeout` | `number` | `30000` | Request timeout in milliseconds | ### Self-hosted API [Section titled “Self-hosted API”](#self-hosted-api) Point the SDK at your own deployment: ```typescript const client = new Tanzanite({ apiKey: "tanzanite_your_key_here", baseUrl: "https://your-self-hosted-api.example.com", }); ``` ## Requirements [Section titled “Requirements”](#requirements) * **Node.js** 18+ (native `fetch`) or any modern browser * **TypeScript** 5.4+ for development ## Next steps [Section titled “Next steps”](#next-steps) * [Sessions](/connecting/sessions/) — lifecycle and control. * [Streaming Events](/connecting/events/) — the planned event reference. # Sessions > Create, reconnect to, and control agent sessions — pause, resume, redirect, cancel, and handle human input. A **session** is one run of an agent toward a goal. You create it, follow its work, optionally answer its questions, and control its execution. ## Creating a session [Section titled “Creating a session”](#creating-a-session) ```typescript const session = await client.createSession({ integrationId: "your_integration_id", goal: "Design a challenging game level", context: { projectId: "proj_1", sceneId: "scene_main" }, }); ``` `context` is arbitrary structured data passed to the agent — use it to scope the run to a project, file, scene, or record. ## Reconnecting [Section titled “Reconnecting”](#reconnecting) Sessions outlive a page refresh. Persist the session ID and reconnect later, then poll for status and new messages: ```typescript const session = await client.getSession(savedSessionId); const info = await session.getInfo(); const { messages } = await session.getMessages({ limit: 50 }); ``` Use `client.getSessionInfo(sessionId)` to read status and cost without creating a full `Session` object. ## Controlling a running session [Section titled “Controlling a running session”](#controlling-a-running-session) ```typescript await session.pause("Need to review progress"); await session.resume({ newBudget: 5.0 }); await session.redirect("Focus on the boss arena instead"); await session.cancel("No longer needed"); ``` ## Human input [Section titled “Human input”](#human-input) When the agent needs a decision, its status becomes `waiting_human`. Respond by input ID with an approval, a choice, or free text: ```typescript // Approval await session.respondToHumanInput(inputId, { approved: true }); // Selection from choices await session.respondToHumanInput(inputId, { choiceId: "option_1" }); // Free text await session.respondToHumanInput(inputId, { freeText: "Medieval theme" }); ``` Note The `inputId` will be delivered on the `human_input_needed` event once [streaming](/connecting/events/) is available. Until then, the response calls above work over REST, but surfacing a pending request’s `inputId` in real time relies on the upcoming stream. ## Inspecting a session [Section titled “Inspecting a session”](#inspecting-a-session) ```typescript const info = await session.getInfo(); console.log(info.status, info.cost); const { messages } = await session.getMessages({ limit: 50 }); ``` ## Next steps [Section titled “Next steps”](#next-steps) * [Streaming Events](/connecting/events/) — the planned event reference. # Agents & Chat > Chat directly with an agent or give it a goal to run an autonomous plan, with subagents, approvals, and live cost tracking. Tanzanite gives you two ways to work with an agent: **Chat** and **Agents** — both in the sidebar. ## Chat [Section titled “Chat”](#chat) Chat is a direct conversation. Ask questions, hand over a file, request a quick edit. The agent has access to the project’s tools and can act immediately (pausing for approval on sensitive actions). Opening **Chat** clears the active project for general, project-free conversation. ## Agents (autonomous runs) [Section titled “Agents (autonomous runs)”](#agents-autonomous-runs) Give an agent a **goal** and it creates a **plan**: it decomposes the goal into steps and executes them, calling tools and producing artifacts along the way. A goal is expressed as an **objective**, optional **verification** criteria, and optional **constraints** (you can also run a quick “one-shot” agent with no formal goal). ![An agent\'s goal — objective, verification, constraints](/_astro/agents-goal.Dg7Vdm5P_HvYTq.webp) *An agent’s objective, verification, and constraints.* ### Subagents [Section titled “Subagents”](#subagents) For larger work, an agent can **spawn subagents** that run in parallel, each scoped to part of the problem, then report back. This keeps long tasks fast and organized. (Internally this is the VEMP plan tree.) ### Approvals and control [Section titled “Approvals and control”](#approvals-and-control) You stay in control of a running plan at all times: * **Approve / edit** sensitive tool calls before they execute. * **Pause** and **resume** (optionally with a new budget). * **Redirect** the agent toward a different focus mid-run. * **Cancel** when you’re done. ### Cost tracking [Section titled “Cost tracking”](#cost-tracking) Every plan tracks token usage and cost as it runs, so there are no surprises. ## Rich output [Section titled “Rich output”](#rich-output) Agents can produce and render markdown, code, images, video, HTML, and PDFs inline through the renderer registry, and can generate media with built-in tools. ## Next steps [Section titled “Next steps”](#next-steps) * Make runs recurring with [Workflows & Schedules](/using/workflows/). * Learn what governs agent behavior in [the Harness](/using/harness/). # Apps > Build small local-first apps that run inside Tanzanite using the window.tanzanite runtime — folder access, peer sync, and on-device AI. **Apps** are small, local-first applications that run inside Tanzanite. They use the `window.tanzanite` runtime to access the file system, sync peer-to-peer, and run AI on-device — without a server. Open **Apps** in the sidebar to browse and launch them from the gallery. ![The Apps gallery](/_astro/apps-gallery.Driksvxe_Z2lCTGA.webp) *The Apps gallery and launcher.* ## The `window.tanzanite` runtime [Section titled “The window.tanzanite runtime”](#the-windowtanzanite-runtime) Apps are static single-page apps that talk to a runtime the desktop shell injects: * **`window.tanzanite.fs`** — read and write files in a folder the user grants. * **`window.tanzanite.peer`** — WebRTC signaling for peer-to-peer sync between users in the same room. * **`window.tanzanite.ai.local`** — on-device AI (text generation, and transcription when available) so prompts never leave the machine. ## Local-first by design [Section titled “Local-first by design”](#local-first-by-design) Apps are built to work offline for a single user and to degrade gracefully when no peers are online. Shared state syncs through CRDTs (Yjs) over encrypted WebRTC data channels, and data at rest is encrypted (AES-GCM). Nothing leaves the machine except encrypted peer-to-peer blobs. This model powers built-in experiences like the notes/PM workspace, where voice messages are transcribed on-device, summarized, organized into subjects, and shared between teammates — all without a backend. ## Building an app [Section titled “Building an app”](#building-an-app) Apps can be created and edited inside Tanzanite with agent assistance. The agent can scaffold the app, wire it to the runtime, and iterate on it with you in a sandboxed preview. ## Next steps [Section titled “Next steps”](#next-steps) * Understand the rules agents follow in [the Harness](/using/harness/). * For programmatic control of agents, see the [SDK](/connecting/sdk-quickstart/). # How cloud agents run > Where a cloud project's agent runs, the device vs. cloud-sandbox backend, the local-file sync mirror, connecting a GitHub repo, and the local-private privacy guarantee. Tanzanite is **cloud-first**. For a **cloud project**, the agent’s reasoning loop always runs on Tanzanite’s servers — but the *tools* it runs (reading files, searching, running commands, committing) execute either **on your own machine** when the desktop app is open, or in a **secure cloud sandbox** when it isn’t. Within those options Tanzanite picks the best one automatically and can switch mid-task without losing work — but running on your machine is something you opt into: it only happens when you’ve linked a local folder and left **“Run agents on this device”** on (see [The local mirror](#the-local-mirror-sync) below). A cloud project with no linked folder runs entirely in the cloud. ## Two kinds of work [Section titled “Two kinds of work”](#two-kinds-of-work) * **Agent work (Type-A)** — planning, editing files, running sub-agents. This always runs in the cloud control plane. Your prompts and the orchestration logic never ship to your browser or into a sandbox. * **Running your code (Type-B)** — actually executing the app or script the agent produced. This can run **locally** (instant, interactive — great for GUIs, games, and tight dev loops) **or** in a **cloud sandbox** (for mobile, offline, or headless/automated runs). ## Where the tools run: device vs. cloud sandbox [Section titled “Where the tools run: device vs. cloud sandbox”](#where-the-tools-run-device-vs-cloud-sandbox) When you have the **desktop app open** and device execution is enabled, the agent runs its file and command tools directly on your local files — fastest, and nothing is cloned. When your device is **closed, offline, you triggered the run from the web/phone, or you haven’t opted into device execution**, the agent runs the very same tools in a **secure cloud sandbox** (a gVisor-isolated pod) over a checkout of your project’s git repo. Because git is the source of truth, switching between the two is seamless: at a safe boundary the agent commits work-in-progress, then points the next tool at the other backend. Close your device mid-run and the work **continues in the cloud**; reopen it and the agent switches back. The run header shows where work is currently happening. ## The local mirror (sync) [Section titled “The local mirror (sync)”](#the-local-mirror-sync) A cloud project’s files live in a git repo that Tanzanite hosts (or your connected GitHub repo). You can optionally **mirror that repo to a local folder** so your edits and the agent’s edits stay in lockstep across devices: * Creating a cloud project does **not** prompt for a folder — a new project has no mirror. Link one any time (desktop only) from the project’s settings under **Local mirror → Link a local folder**. (Importing an existing folder as a new project is a separate flow that starts from the folder.) * When linking, Tanzanite proposes a starter `.gitignore` where recommended — so `node_modules`, build output, and secrets like `.env` are **never** committed — and, if the folder isn’t a git repo yet, initializes one and makes the first commit for you. Right after linking it pulls the cloud repo down into the folder. * At link time you choose **“Run agents on this device”** (on by default). On = the agent runs commands in this folder; off = the folder mirrors for sync only and the agent works entirely in the cloud. You can flip it later, and device execution is available only while a mirror is linked and enabled. * Agent commits flow down like a live `git pull`; your local edits flow up. * **Your local work is never thrown away.** If both sides changed, Tanzanite merges non-overlapping edits automatically; a genuine same-line conflict is surfaced for you to resolve, with your version preserved on a `tz/local/` branch as a safety net. `.gitignore` is always respected, so ignored files never sync, never reach the cloud, and never enter a sandbox. ## Connecting a GitHub repo [Section titled “Connecting a GitHub repo”](#connecting-a-github-repo) Instead of a Tanzanite-hosted repo, a cloud project can be backed by your own **GitHub repository** via the Tanzanite GitHub App: 1. In the project’s **Connectors** settings, click **Install / configure the GitHub App** and grant access to the repos you want. 2. Click **Find my repos** and pick one — the connection is provisioned for you (no IDs to copy). Once connected, cloud runs check the repo out, run real `git`, `commit`, push a branch, and open a **pull request** for your review. The agent only ever has a short-lived, repo-scoped token — never your account credentials. ## Local-private projects (the privacy path) [Section titled “Local-private projects (the privacy path)”](#local-private-projects-the-privacy-path) A **local project** is different: both the model **and** the agent run entirely on your device using an on-device model. Nothing — not your code, not your prompts — leaves your machine. There’s no cloud round-trip, no sandbox, and no sub-agents. It’s the free, zero-cloud path and a genuine privacy guarantee, and it requires the desktop app (the on-device model can’t run in a browser). ## What stays private and secure [Section titled “What stays private and secure”](#what-stays-private-and-secure) * Your provider keys, connector secrets, and credentials live only in Tanzanite’s control plane — they are **never** sent to a sandbox or to your device. * A sandbox only ever holds a short-lived token scoped to the one project’s git repo, and its network access is locked to that repo and the package cache. * For cloud projects, Tanzanite is the single writer of the agent’s record of truth, so your run state is consistent no matter which device you’re on. # The Harness > The harness is the hot-swappable configuration that governs every agent — system prompt, available tools, model routing, and safety guardrails. Every agent in Tanzanite is governed by a **harness**. The harness is the control layer that decides how an agent behaves — and it can be changed without redeploying anything. ## What the harness defines [Section titled “What the harness defines”](#what-the-harness-defines) * **System prompt** — the base instructions every agent starts from. * **Available tools** — which tools the agent can call, organized into tiers so the agent discovers more capabilities as a task requires them. * **Model routing** — which model handles which kind of step. * **Safety guardrails** — what requires approval and what is blocked. ## Hot-swappable [Section titled “Hot-swappable”](#hot-swappable) The harness is configuration, not code. Administrators can edit it in the harness editor (under **Admin**) and the change takes effect for new runs immediately — no build, no deploy. This makes it easy to tune behavior, add tools, or tighten guardrails. ![The harness editor](/_astro/harness-editor.BEnGK4Hd_1o672A.webp) *Editing the harness — available to admins.* ## Skills and plugins [Section titled “Skills and plugins”](#skills-and-plugins) The harness works alongside: * **Skills** — packaged instructions and capabilities an agent can load for specific tasks. * **Plugins** — installable bundles that extend the platform with new tools and integrations. ## Local-private harness [Section titled “Local-private harness”](#local-private-harness) For fully private use, Tanzanite can run a local harness against an on-device model, so sensitive work never leaves your machine. ## Next steps [Section titled “Next steps”](#next-steps) * See the agent surface available to integrators in [Connecting to Tanzanite](/connecting/overview/). # What is Tanzanite > Tanzanite is an AI agent platform that orchestrates autonomous coding and task agents from a native app, governed by a hot-swappable harness. Tanzanite is an AI agent platform. It lets you run autonomous agents that plan, call tools, write and edit files, execute code, and complete multi-step work on your behalf — from a native app on macOS (with iOS and Android in progress). ## How it fits together [Section titled “How it fits together”](#how-it-fits-together) Agents run in the cloud and act on your machine through a secure bridge: * **The app** is where you work — create projects, talk to agents, review and approve their actions, and watch plans run in real time. * **Agents run in the cloud** and stream their reasoning, tool calls, and results back to you live. * **Tool calls reach your machine** through a WebSocket bridge, so an agent can read and write files in a project folder, run commands, and use local capabilities — only with your approval. * **A harness governs every agent.** The harness defines the system prompt, which tools are available, how models are routed, and the safety guardrails. It can be swapped without redeploying anything. ## What you can do [Section titled “What you can do”](#what-you-can-do) Out of the box, Tanzanite supports: * **Projects** — cloud or local working contexts an agent operates in. * **Chat & agents** — direct conversation plus long-running autonomous plans that can spawn subagents for parallel work. * **Workflows & schedules** — multi-step automations and recurring runs. * **Apps** — build small local-first apps that run inside Tanzanite and use the `window.tanzanite` runtime (file access, peer sync, on-device AI). * **Code execution** — run code in sandboxes (Piston, Pyodide, isolated-vm). * **File, image, video, and voice** — upload media, generate it, and dictate. ## Where to go next [Section titled “Where to go next”](#where-to-go-next) * New here? Start with the [Quickstart](/using/quickstart/). * Building an integration or connecting your own agent? See [Connecting to Tanzanite](/connecting/overview/). # Plans & Pricing > The Free, Plus, and Pro plans, prepaid credits, and what unlocks cloud projects. Tanzanite is **usage-based**. You can pay as you go with prepaid credits, or take a monthly plan that includes a usage allotment. Everything is priced in USD and there are no surprises — you only pay for what the agent actually uses. ## Plans [Section titled “Plans”](#plans) | Plan | Price | Included usage / month | Cloud projects | | -------- | --------- | ------------------------ | -------------- | | **Free** | $0 | — (prepaid credits only) | ✘ | | **Plus** | $20 / mo | \~$25 of usage | ✔ | | **Pro** | $200 / mo | \~$300 of usage | ✔ | * **Free** is genuinely free for **local projects** on the desktop app — the on-device model runs entirely on your machine at no cost. With prepaid credits, free users can also use ephemeral chat and media generation. Free accounts **cannot create cloud projects** (see gating below). * **Plus** unlocks **cloud projects** — cloud models and the agent tier (including sub-agents) — and includes about $25 of monthly usage. * **Pro** is for heavier and team usage: a larger monthly allotment and higher limits. ## Credits [Section titled “Credits”](#credits) Credits are **prepaid** and never expire while your account is active. Top up any time. When you’re on a plan, usage draws from your **monthly allotment first**; once that’s exhausted it only draws from credits if you’ve opted in to *fallback to credits* (otherwise the run pauses and prompts you to upgrade or top up). Pay-as-you-go (no plan) usage draws directly from credits. Manage your plan, see your balance, and buy credits from **Account → Billing**. ## What requires a plan (gating) [Section titled “What requires a plan (gating)”](#what-requires-a-plan-gating) Creating or running a **cloud project** requires an active plan (**Plus** or **Pro**). If you’re on the Free plan and try to create a cloud project — or start a cloud run — Tanzanite shows an **upgrade prompt** instead. Local projects are always available on the desktop app, free of charge. This keeps the free tier genuinely free (the on-device model has zero marginal cost) while tying cloud usage — which has real costs — to a paid plan. ## Next steps [Section titled “Next steps”](#next-steps) * Learn the difference between [cloud and local projects](/using/projects/). * See [Agents & Chat](/using/agents-and-chat/) for how runs consume usage. # Projects > Cloud and local projects — the working context agents operate in, including the local bridge for file access. A **project** is the workspace an agent operates in. Everything an agent does — chats, plans, files, and tool calls — happens inside a project. Open **Projects** in the sidebar and click **New Project** to create one. Your projects also appear in the sidebar so you can switch the active project at any time. ![Projects listed in the sidebar](/_astro/projects-list.01M4NK8b_1NywKf.webp) *Switching the active project from the sidebar.* ## Cloud vs. local projects [Section titled “Cloud vs. local projects”](#cloud-vs-local-projects) **Cloud projects** are fully managed. The agent’s working files live in the cloud and nothing is required on your machine. Good for self-contained tasks. Creating a cloud project requires an active **Plus** or **Pro** plan — see [Plans & Pricing](/using/plans-and-pricing/). On the Free plan, Tanzanite shows an upgrade prompt instead. **Local projects** point at a folder on your own computer. When you create one, Tanzanite opens a native folder picker and requests file-system access to that folder. The agent reaches it through the **local bridge** — a secure WebSocket connection between the app and the agent runtime — so it can read, write, and edit your real files. This is what makes Tanzanite useful for working on existing codebases and documents. For local projects you can also configure build, run, and dev commands in the project’s settings. ## The local bridge [Section titled “The local bridge”](#the-local-bridge) When you open a local project, the app exposes file-system tools to the agent over the bridge. The agent can list, read, and write files in that folder only. Sensitive actions surface as **approval requests** before they run. ## Connectors [Section titled “Connectors”](#connectors) Projects can be backed by external sources through **connectors** (for example, a Git repository). Connectors route the agent’s working directory to the right place so it operates against the correct files. ## Next steps [Section titled “Next steps”](#next-steps) * See how [Agents & Chat](/using/agents-and-chat/) run inside a project. * Automate recurring work with [Workflows & Schedules](/using/workflows/). # Quickstart > Install the Tanzanite app, sign in, create your first project, and run your first agent. This guide gets you from zero to a running agent in a few minutes. Note The screenshots below are placeholders. Replace the images in `apps/docs/src/assets/screenshots/` with real captures from the app — the steps and navigation labels already match the shipped macOS build. ## 1. Install the app [Section titled “1. Install the app”](#1-install-the-app) Download the latest Tanzanite build for macOS and open it. Tanzanite runs both as a full window and in your menu bar (system tray). ## 2. Sign in [Section titled “2. Sign in”](#2-sign-in) Create an account or sign in with email and password (or Google). ![The Tanzanite sign-in screen](/_astro/signin.Bsjzzj0C_qIv9z.webp) *The sign-in screen.* You can also sign up programmatically — see [Authentication](/connecting/authentication/). ## 3. Find your way around [Section titled “3. Find your way around”](#3-find-your-way-around) The left **sidebar** is the main navigation: * **Chat** — talk to an agent (clearing the active project for general chat). * **Agents** — long-running autonomous agents and their goals. * **VEMPs** — reusable agent building blocks. * **Projects** — your working contexts (cloud or local). * **Integrations** — connect Tanzanite to other systems. * **Workflows** / **Workflow Runs** — build and monitor automations. * **Apps** — local-first apps that run inside Tanzanite. * **Memory**, **Account**, **Settings** — and **Admin** if you’re an admin. ## 4. Create a project [Section titled “4. Create a project”](#4-create-a-project) Open **Projects** in the sidebar and click **New Project**. Choose: * **Cloud project** — managed working space, nothing needed on your machine. * **Local project** — Tanzanite opens a native folder picker (“Select project folder”) and requests file-system access to that folder so an agent can read and edit those files. ![Projects view with the New Project action](/_astro/new-project.DOc57dxq_kXUMx.webp) *Projects → New Project.* See [Projects](/using/projects/) for the difference between cloud and local. ## 5. Start a chat or a plan [Section titled “5. Start a chat or a plan”](#5-start-a-chat-or-a-plan) With a project active, open **Chat** and either ask a quick question or give the agent a **goal** to kick off an autonomous run. The agent breaks the goal into steps, calls tools, and can spawn subagents for parallel work. ![Chat with a goal entered](/_astro/chat-goal.DVnI1_Kg_YKbAj.webp) *Entering a goal in Chat.* ## 6. Review, approve, and watch it run [Section titled “6. Review, approve, and watch it run”](#6-review-approve-and-watch-it-run) When an agent wants to take a sensitive action (writing files, running a command), it pauses for your approval. The plan tree shows each step live — reasoning, tool calls, results, and cost — and you can pause, resume with a new budget, redirect, or cancel. ![A plan running with an approval prompt](/_astro/plan-tree.aAdTPt55_Zdm5mx.webp) *A live plan with an approval prompt.* ## Next steps [Section titled “Next steps”](#next-steps) * Learn how [Projects](/using/projects/) work. * Set up [Workflows & Schedules](/using/workflows/) for recurring automation. * Understand [the Harness](/using/harness/) that governs agent behavior. # Workflows & Schedules > Build multi-step automations and run agents on a recurring schedule. Beyond one-off chats and plans, Tanzanite lets you define reusable automations and run them on a schedule. ## Workflows [Section titled “Workflows”](#workflows) A **workflow** is a multi-step automation defined once and run many times. The workflow engine executes the steps in order, passing results forward, and can invoke agents as part of the flow. Use workflows for repeatable processes — report generation, data processing, multi-stage reviews. Build workflows under **Workflows** in the sidebar and watch executions under **Workflow Runs**. ![The workflow editor and runs](/_astro/workflows.DKwrbECI_24OOSI.webp) *Workflows and Workflow Runs.* ## Schedules [Section titled “Schedules”](#schedules) A **schedule** runs an agent or workflow automatically on a recurring basis — for example, a morning briefing or a nightly check. Define the goal and the cadence, and Tanzanite handles the rest. ## Triggering from outside [Section titled “Triggering from outside”](#triggering-from-outside) Workflows and agents can also be kicked off by external events — webhooks and channel adapters (such as messaging platforms) — so automations can react to the outside world, not just the clock. Developers can drive these programmatically; see [Connecting to Tanzanite](/connecting/overview/). ## Next steps [Section titled “Next steps”](#next-steps) * Build small in-app tools with [Apps](/using/apps/). * Drive runs from your own code via the [SDK](/connecting/sdk-quickstart/).