The Coline App SDK: apps, tools, file types and surfaces that run inside Coline workspaces, and public websites with Coline Sites. TypeScript, with an in-memory test workspace. MIT.
| 6 |
| 7 | ## Public entry points |
| 8 |
| 9 | - `@colineapp/sdk/v2` is the current app-authoring API: `defineApp`, |
| 10 | `defineTool`, `defineFileType`, `defineCommand`, `ui`, `actions`, manifest |
| 11 | schemas, capability types, and hosted protocol helpers. |
| 12 | - `@colineapp/sdk/testing` provides `createTestWorkspace`, the in-memory |
| 13 | capability fake used by app tests. |
| 14 | - `@colineapp/sdk` is the legacy v1 surface. Do not use it for new apps. |
| 15 |
| 16 | ## Contract map |
| 17 |
| 18 | - `src/define/` extracts and validates an app definition. |
| 19 | - `src/manifest/` defines the consented manifest: permissions, surfaces, |
| 20 | file types, tools, hosting, triggers, and commands. |
| 21 | - `src/capabilities/types.ts` is the transport-neutral `coline.*` contract. |
| 22 | - `src/tree/tree.ts` is the tree UI builder API used by hosted handlers and |
| 23 | Kairo cards. `src/tree/chat-card.ts` defines the stricter chat subset. |
| 24 | - `src/testing/` must stay behaviorally aligned with the capability types. |
| 25 | - `src/server/` signs requests (shared by v1 and v2) and builds the protocol |
| 26 | v2 signed envelope. |
| 27 | - `src/index.ts` and `src/legacy/` are the frozen v1 surface. Do not add to |
| 28 | them. |
| 29 |
| 30 | ## App-authoring rules |
| 31 |
| 32 | ```ts |
| 33 | import { z } from "zod/v4"; |
| 34 | import { defineApp, defineTool, ui } from "@colineapp/sdk/v2"; |
| 35 |
| 36 | const createThing = defineTool({ |
| 37 | name: "things.create_thing", |
| 38 | description: "Create a thing.", |
| 39 | input: z.object({ title: z.string().min(1) }), |
| 40 | effect: "write", |
| 41 | execute: async (input) => ({ |
| 42 | output: { title: input.title }, |
| 43 | card: ui.text(`Created ${input.title}.`), |
| 44 | }), |
| 45 | }); |
| 46 | ``` |
| 47 |
| 48 | - Tool names are app-key-prefixed (`app-key.operation`). |
| 49 | - Validate every tool input with Zod. |
| 50 | - `effect` is an enforced capability ceiling: reads are `read`, mutations are |
| 51 | `write`, destructive actions are `destructive`, and external side effects |
| 52 | are `external`. |
| 53 | - Request the minimum manifest permissions. A tool declaration does not grant |
| 54 | a capability by itself. |
| 55 | - Tree handlers return `ui.*` nodes. React surfaces use `@colineapp/ui`; the |
| 56 | SDK does not provide React components. |
| 57 | - App records are envelopes: `{ id, appId, installId, collection, |
| 58 | createdBy, createdAt, updatedAt, data }`. |
| 59 | - Collection queries support top-level equality/comparison/contains `where`, |
| 60 | `orderBy`, `order`, `limit`, and `cursor`. Keep the fake and backend aligned. |
| 61 |
| 62 | ## Testing and changes |
| 63 |
| 64 | - Test tools with `createTestWorkspace(app).invokeTool(...)`. |
| 65 | - Assert cards with the chat-card validator and state with |
| 66 | `workspace.files`, `workspace.state`, or collection results. |
| 67 | - Run focused checks from the repository root: |
| 68 | `pnpm --filter @colineapp/sdk typecheck` and |
| 69 | `pnpm --filter @colineapp/sdk test`. |
| 70 | - When changing a public type, update the closest unit test and README example |
| 71 | in the same change. Keep v2 behavior transport-neutral. |
| 72 | - Never add a second capability client or a second tree schema. Extend the |
| 73 | canonical types and fake together. |
| 74 |
| 75 | ## Release hygiene |
| 76 |
| 77 | The package ships `dist/` plus this guide. Update the package version and |
| 78 | generated artifacts through the repository release process; never hand-edit a |
| 79 | declaration file to hide a type failure. |
| 80 |
| 81 | ## Shared workspace capabilities |
| 82 |
| 83 | Tasks, calendar events, messages/comments, and references use canonical workspace |
| 84 | objects with explicit domain grants and invoking-user ACLs. App records remain |
| 85 | install-private; share files/references instead of copying work between apps. |
| 86 | `workspace.client()` tests interactive writes; preview/server rendering stays read-only. |
| 87 |
| 88 | ## Live records |
| 89 |
| 90 | Records now carry `version` and `access`. Use `createLiveCollection` for optimistic |
| 91 | views; direct writes should pass `expectedVersion`. Collection `sync` returns a |
| 92 | bounded authorized snapshot or null rows when its durable revision is unchanged. |
| 93 | Do not infer permission from cached data: the host checks every operation. Record |
| 94 | access is enforced in the fake as well as the host. Use `clientAs(userId)` with |
| 95 | `createTestWorkspace(app, { members: [...] })` for multiple-actor tests. |
| 96 | See `docs/sdk/live-data.md` in the product repo and the package README for usage. |
| 97 |
| 98 | ## AI jobs |
| 99 |
| 100 | Use `src/capabilities/ai.ts` for model discovery, durable AI requests and replay. |
| 101 | Apps call `coline.ai`, never a provider SDK with their own credentials. Persist |
| 102 | job IDs and event cursors; use `watchAiJob` to resume. Media uses Coline file IDs |
| 103 | and normal file permissions. Each request requires an idempotency key and an |
| 104 | approved maximum charge. Check model kind/capabilities before offering controls. |
| 105 | For tests, provide `aiModels` and `onAiJob(request, { event })`; the fake never |
| 106 | contacts a provider. Full examples and operator setup are in `docs/sdk/ai.md`. |
| 107 |
| 108 | Collection `orderBy` should name a scalar field. Numbers sort numerically, so |
| 109 | priority 2 precedes 10 in ascending order. In a mixed field, numbers precede |
| 110 | other scalar values; remaining values use case-sensitive text order, with null |
| 111 | and missing values treated as empty text. Descending reverses that order; record |
| 112 | IDs break ties. The server, test workspace, and optimistic live view agree. |
| 113 |
| 114 | ## Full-stack contract (0.6) |
| 115 |
| 116 | - Events: `triggers.webhooks` + `handlers.onEvent`; platform events need their |
| 117 | read permission plus `webhooks.subscribe`; payloads are identifiers only. |
| 118 | - Endpoints (`manifest/endpoints.ts`), jobs (`manifest/jobs.ts`), connections |
| 119 | (`manifest/connections.ts`), and sites (`surfaces.site`, SDK 2.1) each have a |
| 120 | permission; `compareAppSecurityContract` treats new ones as consent changes, |
| 121 | including collections newly opened to site visitors. |
| 122 | - Sites: `manifest/collections.ts` holds the visitor rules, |
| 123 | `capabilities/record-access.ts` (`canVisitorAccess`) is the one predicate the |
| 124 | server, the fake and the dev server share, and `site/` is the browser |
| 125 | client (`@colineapp/sdk/site`). Visitors are `{ kind: "visitor" }` actors. |
| 126 | - Server kinds for external hosting live in `server/kinds.ts`; every kind the |
| 127 | platform dispatches must be handled by `createColineAppHandler`. |
| 128 | - The fake (`testing/`) implements jobs (`runJobs`), events (`fireEvent`), |
| 129 | endpoints (`request`), connections, and site visitors (`invokeSiteTool`, |
| 130 | `asVisitor`); keep it in step with |
| 131 | `apps/web/src/lib/apps/*-ops.ts`. |
| 132 |