Skip to content

cowork.json reference

A folder .cowork/apps/<name>/ with this file is a Cowork app: it shows on the activity bar, brings its routines and file routes, and is what cowork push publishes to a team server.

string

string · required (pattern ^[a-z0-9][a-z0-9-]{0,62}$)

Store identity and activity-bar id: lowercase letters, digits and dashes. Unique within a workspace and within a team server's store.

string · required (maxLength 40, pattern ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$)

Semver X.Y.Z. cowork push publishes exactly this version (and bumps the patch when this version is already published and the files changed).

string (maxLength 200)

Display name: the activity-bar tooltip, the pane title, the store card. Defaults to name. A title starting with a system icon's name (Explorer, Search, Manage Workspace, …) gets no activity-bar icon.

string (maxLength 2000)

One or two sentences for the store card.

string (pattern ^(?:[a-z0-9-]+|\$\([a-z0-9-]+\)|(?![/\\])(?!.*(?:^|/)\.\.?(?:/|$))(?!.*//)[^\\:]+\.(?:[pP][nN][gG]|[sS][vV][gG]|[wW][eE][bB][pP]|[jJ][pP][eE]?[gG]))$)

A codicon id, e.g. "mail", "calendar", "rocket" (https://microsoft.github.io/vscode-codicons/), or an image file inside this folder, e.g. "icon.png" (.png/.svg/.webp/.jpg, at most 256 KB) — shown full-color on the activity-bar tile.

string (pattern ^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$)

Icon tile background on the activity bar, e.g. "#EA4335" (the glyph turns white).

string (pattern \.(jsx|tsx)$)

The app UI, relative to this folder. Present → the app gets an activity-bar icon. A web app has "web" instead — never both.

object

Makes the folder a web app — index — or a site app — url. A web app: a prebuilt static site (an index.html with its scripts, styles, .wasm …) that opens in an editor tab on its own origin, unmodified. Always display "tab". Route files to it with fileRouting → its index, e.g. {"**/*.docx": "web/index.html"}. Opens in the Cowork Studio desktop app and in Cowork in a browser tab or the PWA, served by the Cowork daemon on its own *.app.localhost origin.

  • web.index · string (maxLength 200, pattern ^(?![/\\])(?!.*(?:^|/)\.\.?(?:/|$))(?!.*//)[^\\:]+\.[hH][tT][mM][lL]?$) — The site's page, e.g. "web/index.html" — its folder is what is served. Relative to this folder; with download, relative to the downloaded build instead (a zip whose files sit in one top folder has that folder stripped), so usually "index.html" — and a build copied into this folder as web/<index> wins over the download.
  • web.open · string (maxLength 200, pattern ^drop:\S) — Only for an app that opens a file just by a drop: "drop:<css selector>", e.g. "drop:#canvas" — the opened file is dropped on that element. Apps that open files through a file picker or an <input type=file> need nothing here.
  • web.download · object — Where the build comes from, so the app folder stays small: fetched on the first open, verified, unpacked and cached once per sha256. index is then relative to the build.
    • web.download.url · string required (maxLength 2048, pattern ^https://) — The build's zip, e.g. a GitHub release asset.
    • web.download.sha256 · string required (pattern ^[0-9a-fA-F]{64}$) — The zip's SHA-256 (shasum -a 256 <file>): checked before anything is unpacked.
  • web.url · string (maxLength 2048, pattern ^(https://|http://(localhost|127\.0\.0\.1|\[::1\])([:/]|$))) — Makes the folder a site app instead: the address of a web site (e.g. "https://chat.example.com/") that opens in an app tab of the Cowork Studio desktop app — or in a side bar pane, with display "right" or "sidebar" — signed in with your browser's accounts — its notifications and its unread count become the app's. https (http only on localhost), no user or password. Never together with index; open, download and fileRouting do not apply.
  • web.scope · string (maxLength 2048, pattern ^(https://|http://(localhost|127\.0\.0\.1|\[::1\])([:/]|$))) — A site app's pages: a start of url on its origin, e.g. "https://example.com/app/". Default: url up to its last "/".

"sidebar" | "tab" | "modal" | "right" (default "sidebar")

Where the app shows. sidebar = in a pane of the left side bar, opened by its activity-bar icon; tab = in an editor tab (no side panel); modal = in a dialog; right = in a pane of the right side bar, a tab of its own there beside Chat (no activity-bar icon). A site app (web.url) is tab by default and may be sidebar or right, the site drawn in the pane; a web app (web.index) is always tab.

string | object

Sidebar apps only: what to open in the editor when the icon is first clicked — an app file in this folder, or a routine that returns {path}.

  • open.routine · string required (pattern ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$)
  • open.args · object

{ [key: string]: string | object }

Routine id → .ts file in this folder, or {"file": "x.ts", "description": "…", "readOnly": true, "input": {…}, "timeout": 120} to say what it does or give it longer than 30 s. Apps call them with cowork.routines.run(id, args). An agent sees each routine of a capability as a tool, by its description and input: a readOnly one it may run unless the person turns it off, any other only once the person allows it.

  • routines.file · string required (pattern \.(ts|js|mjs)$)
  • routines.description · string (maxLength 400) — One line on what it does — what an agent reads to pick it.
  • routines.readOnly · boolean (default false) — It changes nothing (lists, opens, looks up): no write at the service, no money spent, no user code run, nothing written in the workspace but its own cache. Every agent may run it unless the person turns it off, and an agent's app may run it without asking — when in doubt it is not a read. Never together with destructive or reachesOthers.
  • routines.destructive · boolean (default false) — What it changes cannot be undone (deletes, refunds).
  • routines.reachesOthers · boolean (default false) — It reaches people beyond the account (sends, posts, pays).
  • routines.input · object — Its arguments as a JSON Schema, at most 8 KB: {"type": "object", "properties": {"query": {"type": "string", "description": "…"}}, "required": ["query"]}. Leave it out for a routine that takes none.
    • routines.input.type · any required
    • routines.input.properties · object
  • routines.timeout · integer (minimum 1, maximum 300) — How long one run may take, in seconds (default 30). Runs from apps, agents (cowork routine run), schedules and webhooks all honor it.

{ [key: string]: string }

Workspace-relative glob → app file in this folder that renders matching files (e.g. "**/*.maillist.json": "mail-list.jsx"). A glob ending in / routes folders instead ("Notebook/": "notebook.jsx" opens when the folder is clicked). An .html value opens the file in this app's web app and must be its web.index.

("web" | "desktop")[] (maxItems 1)

Where the app can run. ["desktop"] = Cowork Studio only (e.g. it drives the embedded browser). Empty = anywhere.

string[] (maxItems 20)

string (pattern ^(?![/\\])(?!.*(?:^|/)\.\.?(?:/|$))(?!.*//)[^\\:]+\.(?:[pP][nN][gG]|[sS][vV][gG]|[wW][eE][bB][pP]|[jJ][pP][eE]?[gG])$)

The store listing's wide picture: an image file inside this folder, e.g. "art/banner.png" (.png/.svg/.webp/.jpg, at most 1 MB). cowork push uploads it.

string[] (maxItems 5)

The store listing's screenshots, in order: image files inside this folder (.png/.svg/.webp/.jpg, at most 1 MB each). cowork push uploads them and clears any the store holds beyond them.

object

One item in the footer (status bar), drawn from what a routine of this app returns. Widgets read it with cowork.statusBar.get(name) and can refresh or click it.

  • statusBar.routine · string required (pattern ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$) — One of this app's routines. It returns the item — {text, icon?, tooltip?, tone?: "warning"|"error", click?: {args, confirm?}, menu?: [{label, args, confirm?}], data?} — or null to hide it. A click runs the same routine with the click's args.
  • statusBar.args · object — What the routine gets when the item refreshes. Default {}.
  • statusBar.interval · integer (default 60, minimum 15, maximum 3600) — Seconds between refreshes while the window has focus (it also refreshes when focus returns and after a click).

object

How this capability connects to its service: a sign-in (oauth), a pasted key (key), or either. The person connects once in Manage Workspace › Components › Credentials, and its routines call the service with ctx.credential. A capability's only — an app's is ignored, with a problem line: it reaches the connections of the capabilities it uses.

  • credential.oauth · object
    • credential.oauth.provider · "google" | "microsoft" required — The service it signs in to: "google" or "microsoft" (a provider the OAuth engine has a preset for).
    • credential.oauth.scopes · string[] required (maxItems 32) — The access its routines need. Every capability signing in to the same provider shares ONE sign-in; connecting asks for what they all need together.
    • credential.oauth.ownClient · boolean — It signs in through its own OAuth client (the person's own Cloud project), under its own name, instead of the shared sign-in.
  • credential.key · object
    • credential.key.fields · string[] required (minItems 1, maxItems 8) — What the person pastes, e.g. ["token"].
    • credential.key.url · string (maxLength 2048, pattern ^https://) — Where to get it, e.g. the service's API keys page.
    • credential.key.hint · string (maxLength 200) — One line on how, shown beside the form.

("screen" | "system-audio" | "mic" | "screenshot")[]

What the app's panes may capture (each still asked for in Cowork's dialog): a recording with video needs "screen", its audio "system-audio" and/or "mic"; a still needs "screenshot". Not on a capability.

"app" | "capability" (default "app")

app = something people open; capability = a package of routines that apps use and agents call as tools — no entry, no fileRouting, no uses of its own. Manage Workspace lists capabilities under Components › Capabilities; it never changes what the package registers.

{ [key: string]: string } (maxProperties 8)

The capabilities this app needs: capability name → the lowest version it works with, e.g. {"gmail": "0.2.0"} (met by the same major at that version or above). Manage Workspace › Components › Capabilities shows any that are missing, switched off or too old.