# SDK package agent guide This package is the public Coline App SDK. Treat its exported TypeScript types, tests, and README as the source of truth for app authors. Do not use private `apps/web` code or first-party apps to invent public API behavior. ## Public entry points - `@colineapp/sdk/v2` is the current app-authoring API: `defineApp`, `defineTool`, `defineFileType`, `defineCommand`, `ui`, `actions`, manifest schemas, capability types, and hosted protocol helpers. - `@colineapp/sdk/testing` provides `createTestWorkspace`, the in-memory capability fake used by app tests. - `@colineapp/sdk` is the legacy v1 surface. Do not use it for new apps. ## Contract map - `src/define/` extracts and validates an app definition. - `src/manifest/` defines the consented manifest: permissions, surfaces, file types, tools, hosting, triggers, and commands. - `src/capabilities/types.ts` is the transport-neutral `coline.*` contract. - `src/tree/tree.ts` is the tree UI builder API used by hosted handlers and Kairo cards. `src/tree/chat-card.ts` defines the stricter chat subset. - `src/testing/` must stay behaviorally aligned with the capability types. - `src/server/` signs requests (shared by v1 and v2) and builds the protocol v2 signed envelope. - `src/index.ts` and `src/legacy/` are the frozen v1 surface. Do not add to them. ## App-authoring rules ```ts import { z } from "zod/v4"; import { defineApp, defineTool, ui } from "@colineapp/sdk/v2"; const createThing = defineTool({ name: "things.create_thing", description: "Create a thing.", input: z.object({ title: z.string().min(1) }), effect: "write", execute: async (input) => ({ output: { title: input.title }, card: ui.text(`Created ${input.title}.`), }), }); ``` - Tool names are app-key-prefixed (`app-key.operation`). - Validate every tool input with Zod. - `effect` is an enforced capability ceiling: reads are `read`, mutations are `write`, destructive actions are `destructive`, and external side effects are `external`. - Request the minimum manifest permissions. A tool declaration does not grant a capability by itself. - Tree handlers return `ui.*` nodes. React surfaces use `@colineapp/ui`; the SDK does not provide React components. - App records are envelopes: `{ id, appId, installId, collection, createdBy, createdAt, updatedAt, data }`. - Collection queries support top-level equality/comparison/contains `where`, `orderBy`, `order`, `limit`, and `cursor`. Keep the fake and backend aligned. ## Testing and changes - Test tools with `createTestWorkspace(app).invokeTool(...)`. - Assert cards with the chat-card validator and state with `workspace.files`, `workspace.state`, or collection results. - Run focused checks from the repository root: `pnpm --filter @colineapp/sdk typecheck` and `pnpm --filter @colineapp/sdk test`. - When changing a public type, update the closest unit test and README example in the same change. Keep v2 behavior transport-neutral. - Never add a second capability client or a second tree schema. Extend the canonical types and fake together. ## Release hygiene The package ships `dist/` plus this guide. Update the package version and generated artifacts through the repository release process; never hand-edit a declaration file to hide a type failure. ## Shared workspace capabilities Tasks, calendar events, messages/comments, and references use canonical workspace objects with explicit domain grants and invoking-user ACLs. App records remain install-private; share files/references instead of copying work between apps. `workspace.client()` tests interactive writes; preview/server rendering stays read-only. ## Live records Records now carry `version` and `access`. Use `createLiveCollection` for optimistic views; direct writes should pass `expectedVersion`. Collection `sync` returns a bounded authorized snapshot or null rows when its durable revision is unchanged. Do not infer permission from cached data: the host checks every operation. Record access is enforced in the fake as well as the host. Use `clientAs(userId)` with `createTestWorkspace(app, { members: [...] })` for multiple-actor tests. See `docs/sdk/live-data.md` in the product repo and the package README for usage. ## AI jobs Use `src/capabilities/ai.ts` for model discovery, durable AI requests and replay. Apps call `coline.ai`, never a provider SDK with their own credentials. Persist job IDs and event cursors; use `watchAiJob` to resume. Media uses Coline file IDs and normal file permissions. Each request requires an idempotency key and an approved maximum charge. Check model kind/capabilities before offering controls. For tests, provide `aiModels` and `onAiJob(request, { event })`; the fake never contacts a provider. Full examples and operator setup are in `docs/sdk/ai.md`. Collection `orderBy` should name a scalar field. Numbers sort numerically, so priority 2 precedes 10 in ascending order. In a mixed field, numbers precede other scalar values; remaining values use case-sensitive text order, with null and missing values treated as empty text. Descending reverses that order; record IDs break ties. The server, test workspace, and optimistic live view agree. ## Full-stack contract (0.6) - Events: `triggers.webhooks` + `handlers.onEvent`; platform events need their read permission plus `webhooks.subscribe`; payloads are identifiers only. - Endpoints (`manifest/endpoints.ts`), jobs (`manifest/jobs.ts`), connections (`manifest/connections.ts`), and sites (`surfaces.site`, SDK 2.1) each have a permission; `compareAppSecurityContract` treats new ones as consent changes, including collections newly opened to site visitors. - Sites: `manifest/collections.ts` holds the visitor rules, `capabilities/record-access.ts` (`canVisitorAccess`) is the one predicate the server, the fake and the dev server share, and `site/` is the browser client (`@colineapp/sdk/site`). Visitors are `{ kind: "visitor" }` actors. - Server kinds for external hosting live in `server/kinds.ts`; every kind the platform dispatches must be handled by `createColineAppHandler`. - The fake (`testing/`) implements jobs (`runJobs`), events (`fireEvent`), endpoints (`request`), connections, and site visitors (`invokeSiteTool`, `asVisitor`); keep it in step with `apps/web/src/lib/apps/*-ops.ts`.