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.
| 4 |
| /** |
| 5 | * The capability operation descriptor table (plan §8, §10.3). |
| 6 | * |
| 7 | * Every capability call is classified once, here: which permission it |
| 8 | * requires and which mutation class it is. The unified guard in apps/web |
| 9 | * and every transport-side gate consume this single table — there is no |
| 10 | * second classification anywhere. |
| 11 | * |
| 12 | * Notes on classifications: |
| 13 | * - `pickers.*` and `navigation.*` need no permission: they are |
| 14 | * host-mediated consent (the user's pick IS the grant, plan §7.2.3). |
| 15 | * - `ai.generate` is `read`: metered and billed, but not a workspace |
| 16 | * mutation. |
| 17 | * - `storage.kv.delete` is `write` (ephemeral app state); |
| 18 | * `storage.records.delete` is `destructive` (user-meaningful work). |
| 19 | */ |
| 20 |
| 21 | export interface AppCapabilityDescriptor { |
| 22 | permission: AppPermissionV2 | null; |
| 23 | mutation: MutationClass; |
| 24 | } |
| 25 |
| 26 | export const APP_CAPABILITY_OPERATIONS = { |
| 27 | "tasks.list": { permission: "tasks.read", mutation: "read" }, |
| 28 | "tasks.get": { permission: "tasks.read", mutation: "read" }, |
| 29 | "tasks.board": { permission: "tasks.read", mutation: "read" }, |
| 30 | "tasks.create": { permission: "tasks.write", mutation: "write" }, |
| 31 | "tasks.update": { permission: "tasks.write", mutation: "write" }, |
| 32 | "tasks.delete": { permission: "tasks.write", mutation: "destructive" }, |
| 33 | "calendar.list": { permission: "calendar.read", mutation: "read" }, |
| 34 | "calendar.get": { permission: "calendar.read", mutation: "read" }, |
| 35 | "calendar.create": { permission: "calendar.write", mutation: "write" }, |
| 36 | "calendar.update": { permission: "calendar.write", mutation: "write" }, |
| 37 | "calendar.delete": { permission: "calendar.write", mutation: "destructive" }, |
| 38 | "messages.list": { permission: "messages.read", mutation: "read" }, |
| 39 | "messages.send": { permission: "messages.write", mutation: "write" }, |
| 40 | "references.resolve": { permission: "references.read", mutation: "read" }, |
| 41 | "tools.invoke": { permission: "ai.tools", mutation: "write" }, |
| 42 | "workspace.get": { permission: null, mutation: "read" }, |
| 43 |
| 44 | "members.list": { permission: "members.read", mutation: "read" }, |
| 45 | "members.get": { permission: "members.read", mutation: "read" }, |
| 46 |
| 47 | "files.list": { permission: "files.read", mutation: "read" }, |
| 48 | "files.get": { permission: "files.read", mutation: "read" }, |
| 49 | "files.getDocument": { permission: "files.read", mutation: "read" }, |
| 50 | "files.create": { permission: "files.write", mutation: "write" }, |
| 51 | "files.update": { permission: "files.write", mutation: "write" }, |
| 52 | "files.updateDocument": { permission: "files.write", mutation: "write" }, |
| 53 | "files.trash": { permission: "files.write", mutation: "destructive" }, |
| 54 |
| 55 | "drives.getAppDrive": { permission: "drives.app", mutation: "read" }, |
| 56 |
| 57 | "storage.kv.get": { permission: "storage.app", mutation: "read" }, |
| 58 | "storage.kv.list": { permission: "storage.app", mutation: "read" }, |
| 59 | "storage.kv.set": { permission: "storage.app", mutation: "write" }, |
| 60 | "storage.kv.delete": { permission: "storage.app", mutation: "write" }, |
| 61 | "storage.records.sync": { permission: "storage.app", mutation: "read" }, |
| 62 | "storage.records.setAccess": { permission: "storage.app", mutation: "destructive" }, |
| 63 | "storage.records.get": { permission: "storage.app", mutation: "read" }, |
| 64 | "storage.records.query": { permission: "storage.app", mutation: "read" }, |
| 65 | "storage.records.insert": { permission: "storage.app", mutation: "write" }, |
| 66 | "storage.records.update": { permission: "storage.app", mutation: "write" }, |
| 67 | "storage.records.delete": { permission: "storage.app", mutation: "destructive" }, |
| 68 |
| 69 | "search.query": { permission: "search.query", mutation: "read" }, |
| 70 | "search.index.upsert": { permission: "search.index", mutation: "write" }, |
| 71 | "search.index.delete": { permission: "search.index", mutation: "write" }, |
| 72 |
| 73 | "notifications.create": { permission: "notifications.write", mutation: "write" }, |
| 74 |
| 75 | "ai.generate": { permission: "ai.generate", mutation: "read" }, |
| 76 |
| 77 | "pickers.file": { permission: null, mutation: "read" }, |
| 78 | "pickers.member": { permission: null, mutation: "read" }, |
| 79 | "pickers.confirm": { permission: null, mutation: "read" }, |
| 80 |
| 81 | "navigation.openFile": { permission: null, mutation: "read" }, |
| 82 | "navigation.openAppHome": { permission: null, mutation: "read" }, |
| 83 | "navigation.navigate": { permission: null, mutation: "read" }, |
| 84 | "navigation.openReference": { permission: null, mutation: "read" }, |
| 85 |
| 86 | "realtime.subscribe": { permission: "realtime.subscribe", mutation: "read" }, |
| 87 | "realtime.publish": { permission: "realtime.subscribe", mutation: "write" }, |
| 88 |
| 89 | // External network (plan §8, M2): host-proxied fetch, gated by the |
| 90 | // network.external permission and the manifest host allowlist. Classed |
| 91 | // read for the ceiling (it mutates nothing in the workspace); the |
| 92 | // allowlist + permission are the actual boundary, and Kairo tools that |
| 93 | // reach out still declare effect "external" for approval gating. |
| 94 | "net.fetch": { permission: "network.external", mutation: "read" }, |
| 95 |
| 96 | "events.emit": { permission: "events.emit", mutation: "write" }, |
| 97 | } as const satisfies Record<string, AppCapabilityDescriptor>; |
| 98 |
| 99 | export type AppCapabilityOperation = keyof typeof APP_CAPABILITY_OPERATIONS; |
| 100 |
| 101 | export function isAppCapabilityOperation(value: string): value is AppCapabilityOperation { |
| 102 | return Object.hasOwn(APP_CAPABILITY_OPERATIONS, value); |
| 103 | } |
| 104 |