CoworkRoutineContext
The context a routine's default export receives:
export default async (args, ctx: CoworkRoutineContext) => result. A deployed routine
(cowork deploy) gets CoworkDeployedRoutineContext instead.
Properties
Section titled “Properties”auth: object;Who is signed into Cowork, and their short-lived Firebase ID token. Read on every call (the token rotates hourly — never keep one from the start of a long run).
getIdToken
Section titled “getIdToken”getIdToken: () => Promise<string | null>;The ID token to call an authenticated API with — null when signed out, or when the token is too close to expiring to be trusted.
Returns
Section titled “Returns”Promise<string | null>
getState
Section titled “getState”getState: () => Promise<{ authenticated: boolean; user: | { displayName: string | null; email: string | null; uid: string; } | null;}>;authenticated and the account (user), or user: null when nobody is signed in.
Returns
Section titled “Returns”Promise<{
authenticated: boolean;
user: | {
displayName: string | null;
email: string | null;
uid: string;
}
| null;
}>
badge: (count) => Promise<void>;This routine's app's count on the OS badge — as cowork.badge: latest wins,
0 clears. Report it on every poll: await ctx.badge(unread).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
count |
number |
Returns
Section titled “Returns”Promise<void>
browser
Section titled “browser”browser: object;The desktop app's built-in browser, step by step: snapshot() lists the page's
actionable elements with refs (ref_3 button "Sign in"), then click / fill / type
/ waitFor act on a ref or a CSS selector. Pages keep the user's own sign-ins, so
evaluate can call a site's API with its cookies. Only in the desktop app: without it
every call throws BrowserUnavailableError (status() is the cheap check); a failed
action throws with the browser's message. Calls without a tabIndex act on the active
tab.
back: () => Promise<{ ok: boolean; url: string;}>;Returns
Section titled “Returns”Promise<{
ok: boolean;
url: string;
}>
click: (refOrSelector) => Promise<{ found: boolean; label?: string; role?: string;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
refOrSelector |
string |
Returns
Section titled “Returns”Promise<{
found: boolean;
label?: string;
role?: string;
}>
evaluate
Section titled “evaluate”evaluate: <T>(js, opts?) => Promise<T>;Run JS in a tab and get its FULL value back (any size; JSON-serializable). js is the
body of an async function — use return. fetch inside it sends the page's cookies,
so open the tab on the origin you mean to call first. tabIndex (from tabs.list())
runs in that tab WITHOUT activating it — resolve it each run, indices shift when tabs
close. world: "isolated" (default — same DOM and cookies, separate globals, the page
cannot see the script) or "main" (the site's own globals).
Type Parameters
Section titled “Type Parameters”| Type Parameter | Default type |
|---|---|
T |
unknown |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
js |
string |
opts? |
{ tabIndex?: number; world?: "isolated" | "main"; } |
opts.tabIndex? |
number |
opts.world? |
"isolated" | "main" |
Returns
Section titled “Returns”Promise<T>
fill: (refOrSelector, value, submit?) => Promise<{ found: boolean; ok?: boolean; value?: string;}>;Set a form field (text / select / checkbox / radio) the way a user would, so
framework-controlled inputs keep the value; submit presses Enter after.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
refOrSelector |
string |
value |
string |
submit? |
boolean |
Returns
Section titled “Returns”Promise<{
found: boolean;
ok?: boolean;
value?: string;
}>
find: (query, limit?) => Promise<{ matches: object[]; query: string;}>;Elements whose label matches query, with their refs (limit: default 10, at most 50).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
query |
string |
limit? |
number |
Returns
Section titled “Returns”Promise<{
matches: object[];
query: string;
}>
forward
Section titled “forward”forward: () => Promise<{ ok: boolean; url: string;}>;Returns
Section titled “Returns”Promise<{
ok: boolean;
url: string;
}>
hover: (refOrSelector) => Promise<{ found: boolean;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
refOrSelector |
string |
Returns
Section titled “Returns”Promise<{
found: boolean;
}>
inject
Section titled “inject”inject: (spec) => Promise<{ id: string; ok: boolean; persist: boolean; url: string; value: unknown; world: string;}>;Apply CSS and/or JS to the page. world as in evaluate; persist re-applies after
every navigation (an app that re-renders on each click); the same id replaces an
earlier injection. value is the script's completion value, cut at 4096 characters —
use evaluate for anything long. tabIndex targets a tab without activating it.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
spec |
{ css?: string; id?: string; js?: string; persist?: boolean; tabIndex?: number; world?: "isolated" | "main"; } |
spec.css? |
string |
spec.id? |
string |
spec.js? |
string |
spec.persist? |
boolean |
spec.tabIndex? |
number |
spec.world? |
"isolated" | "main" |
Returns
Section titled “Returns”Promise<{
id: string;
ok: boolean;
persist: boolean;
url: string;
value: unknown;
world: string;
}>
injections
Section titled “injections”injections: () => Promise<{ injections: object[];}>;Returns
Section titled “Returns”Promise<{
injections: object[];
}>
navigate
Section titled “navigate”navigate: (url) => Promise<{ ok: boolean; url: string;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url |
string |
Returns
Section titled “Returns”Promise<{
ok: boolean;
url: string;
}>
open: (url?) => Promise<{ ok: boolean; url: string;}>;A URL opens in a new tab; no URL shows the browser (its last-active tab, or a new one).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url? |
string |
Returns
Section titled “Returns”Promise<{
ok: boolean;
url: string;
}>
press: (key) => Promise<{ key: string; ok: boolean;}>;"Return", "Tab", "cmd+a", …
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
key |
string |
Returns
Section titled “Returns”Promise<{
key: string;
ok: boolean;
}>
read: (maxChars?) => Promise<{ text: string; title: string; url: string;}>;The page's visible text (maxChars: default 20000, at most 100000).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
maxChars? |
number |
Returns
Section titled “Returns”Promise<{
text: string;
title: string;
url: string;
}>
reload
Section titled “reload”reload: () => Promise<{ ok: boolean; url: string;}>;Returns
Section titled “Returns”Promise<{
ok: boolean;
url: string;
}>
screenshot
Section titled “screenshot”screenshot: () => Promise<{ height: number; path: string; width: number;}>;A JPEG of the page, written to a temporary file — its path.
Returns
Section titled “Returns”Promise<{
height: number;
path: string;
width: number;
}>
scroll
Section titled “scroll”scroll: (opts?) => Promise<{ scrolledTo?: string; scrollY?: number;}>;Scroll an element into view (ref), or the page by dy pixels (default 600).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts? |
{ dy?: number; ref?: string; } |
opts.dy? |
number |
opts.ref? |
string |
Returns
Section titled “Returns”Promise<{
scrolledTo?: string;
scrollY?: number;
}>
snapshot
Section titled “snapshot”snapshot: (maxNodes?) => Promise<{ elements: string[]; title: string; truncated: boolean; url: string;}>;One line per actionable element (ref_3 button "Sign in") — the refs every other call
targets. truncated when the page had more than maxNodes.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
maxNodes? |
number |
Returns
Section titled “Returns”Promise<{
elements: string[];
title: string;
truncated: boolean;
url: string;
}>
status
Section titled “status”status: () => Promise<{ host?: "pane" | "tabs"; open: boolean; shell?: string; tabs: object[];}>;Whether the browser has tabs open, and which.
Returns
Section titled “Returns”Promise<{
host?: "pane" | "tabs";
open: boolean;
shell?: string;
tabs: object[];
}>
tabs: object;tabs.activate
Section titled “tabs.activate”activate: (index) => Promise<{ active: number;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
index |
number |
Returns
Section titled “Returns”Promise<{
active: number;
}>
tabs.close
Section titled “tabs.close”close: (index) => Promise<{ count: number;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
index |
number |
Returns
Section titled “Returns”Promise<{
count: number;
}>
tabs.list
Section titled “tabs.list”list: () => Promise<{ tabs: object[];}>;Returns
Section titled “Returns”Promise<{
tabs: object[];
}>
tabs.new
Section titled “tabs.new”new: (url?, opts?) => Promise<{ count: number; existing?: boolean; id?: string; index: number;}>;A new tab (on url, if given). opts.id asks for that tab: when it is still open
it is answered (existing: true) instead of opening a second one.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url? |
string |
opts? |
{ id?: string; } |
opts.id? |
string |
Returns
Section titled “Returns”Promise<{
count: number;
existing?: boolean;
id?: string;
index: number;
}>
toggle
Section titled “toggle”toggle: (show?) => Promise<{ open: boolean;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
show? |
boolean |
Returns
Section titled “Returns”Promise<{
open: boolean;
}>
type: (text, refOrSelector?, submit?) => Promise<{ found: boolean; ok: boolean;}>;Type text into the element (or the focused one); submit presses Enter after.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
text |
string |
refOrSelector? |
string |
submit? |
boolean |
Returns
Section titled “Returns”Promise<{
found: boolean;
ok: boolean;
}>
uninject
Section titled “uninject”uninject: (id?) => Promise<{ ok: boolean; removed: string[];}>;Remove one injection by id, or all of them. CSS goes; a script that already ran cannot be un-run — its effects last until the page reloads.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id? |
string |
Returns
Section titled “Returns”Promise<{
ok: boolean;
removed: string[];
}>
waitFor
Section titled “waitFor”waitFor: (opts) => Promise<{ error?: string; ok: boolean; waitedMs?: number;}>;Wait until text appears or an element (ref) exists — the deterministic gate after
a click that loads something (timeoutMs: default 10000, at most 20000).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts |
{ ref?: string; text?: string; timeoutMs?: number; } |
opts.ref? |
string |
opts.text? |
string |
opts.timeoutMs? |
number |
Returns
Section titled “Returns”Promise<{
error?: string;
ok: boolean;
waitedMs?: number;
}>
command
Section titled “command”command: object;Run a terminal command, gated by a consent MODAL. Cowork
asks the user to approve (a native modal: Allow once / Always allow
in this workspace / Cancel), then runs command in the workspace
folder through a LOGIN shell
(PATH like a terminal, so gcloud/brew bins resolve and gcloud auth login opens the default browser itself) and resolves { code, stdout, stderr }. The modal text is yours to set: title (heading) + description
(one line framing the ask); the command is always shown under "Command:".
Consent is keyed on value — a STABLE label, so a variable arg (e.g. a VM
IP) won't defeat a prior "Always allow"; defaults to the command. Grants
live in Cowork's per-workspace consent file, on this computer, NEVER in the
workspace — every machine approves the first time. A Deny (or an unanswered prompt) rejects
(ConsentRequired). For a long-lived interactive process use a stream instead.
run: (command, opts?) => Promise<{ code: number; stderr: string; stdout: string;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
command |
string |
opts? |
{ description?: string; timeoutMs?: number; title?: string; value?: string; } |
opts.description? |
string |
opts.timeoutMs? |
number |
opts.title? |
string |
opts.value? |
string |
Returns
Section titled “Returns”Promise<{
code: number;
stderr: string;
stdout: string;
}>
consent
Section titled “consent”consent: object;Consent-ONLY request — the same native modal as command.run, but nothing
executes: the routine gets { granted, ticket? } to attach to a
consent-gated call (e.g. hand it to the widget for stream.open). value
is the stable consent label ("Always allow" persists it to USER DATA);
command is what the modal displays under "Command:". Deny or an
unanswered prompt → { granted: false } — never a throw. With no Cowork window
open to ask, reason says so and names the cowork consent allow command that
approves it instead.
request
Section titled “request”request: (opts) => Promise<{ granted: boolean; reason?: string; ticket?: string;}>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts |
{ command?: string; description?: string; title?: string; value: string; } |
opts.command? |
string |
opts.description? |
string |
opts.title? |
string |
opts.value |
string |
Returns
Section titled “Returns”Promise<{
granted: boolean;
reason?: string;
ticket?: string;
}>
credential
Section titled “credential”credential: object;This capability's connection — the one its cowork.json "credential" declares: a sign-in,
a pasted key, or either. A capability declaring none gets NotConnected saying so; an app's
routine, NotGranted (it calls its capability's routines with ctx.routines.run). A call that
needs it connected throws NotConnected naming where the person connects it.
disconnect
Section titled “disconnect”disconnect: () => Promise<{ removed: string[]; revoked: boolean;}>;Forget it, revoked at the service when it can be — for every capability that shares it.
Returns
Section titled “Returns”Promise<{
removed: string[];
revoked: boolean;
}>
fetch: (url, init?) => Promise<Response>;An authenticated fetch to the service. A sign-in sends its bearer — a 401 refreshes the
token once and retries; only to the service's API hosts, https. A key sends nothing by
itself: put its header in init.headers. A 429 or 5xx waits and retries retries times
(0–4, default 2; 0 for a write that must never repeat); json is sent as the JSON body.
Resolves with the Response whatever its status; throws NotConnected while it is not
connected (or the service refused the saved sign-in) and BadRequest for a URL a sign-in
may not be sent to.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
url |
string | URL |
init? |
RequestInit & object |
Returns
Section titled “Returns”Promise<Response>
fields
Section titled “fields”fields: () => Record<string, string>;A key's fields by name, e.g. { token } — NotConnected naming the ones not pasted yet.
Returns
Section titled “Returns”Record<string, string>
start: () => Promise<{ authUrl: string;}>;Begin a sign-in: the consent URL to open in a browser. A key is pasted in Manage Workspace, never through a routine.
Returns
Section titled “Returns”Promise<{
authUrl: string;
}>
status
Section titled “status”status: () => object;Whether it is connected with everything this capability asks for, and as whom — never a token.
Returns
Section titled “Returns”object
account?
Section titled “account?”account?: object;account.email
Section titled “account.email”email: string;connected
Section titled “connected”connected: boolean;token: (opts?) => Promise<string>;A sign-in's access token, refreshed when needed ({ force: true } after the service
answered 401); a key's first field. Prefer fetch.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts? |
{ force?: boolean; } |
opts.force? |
boolean |
Returns
Section titled “Returns”Promise<string>
data: object;The app's own data folder, .cowork/data/<app name>/ (it travels with the
workspace): names are paths inside it ("Gmail.json", "records/acme.json"). Keep user
data here, not in the app folder, so the app stays clean and updates itself. A routine
outside an app (.cowork/apps/<name>/) has no data folder: dir is "" and every call
that touches a file throws (fileName, which only builds a name, still works).
readonly dir: string;Workspace-relative: .cowork/data/<app>.
fileName
Section titled “fileName”fileName: (title, fallback) => string;A title as a safe file name (≤ 60 characters), or fallback.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
title |
unknown |
fallback |
string |
Returns
Section titled “Returns”string
list: (subdir?) => string[];The files in the folder or a subfolder, sorted (dot files left out).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
subdir? |
string |
Returns
Section titled “Returns”string[]
path: (name) => string;A name's workspace-relative path — what cowork.openFile and fileRouting take.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
Returns
Section titled “Returns”string
read: <T>(name, fallback?) => T;A JSON file's value; fallback when it is missing or not JSON.
Type Parameters
Section titled “Type Parameters”| Type Parameter | Default type |
|---|---|
T |
unknown |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
fallback? |
T |
Returns
Section titled “Returns”T
remove
Section titled “remove”remove: (name) => boolean;Delete a file; false when there was none.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
Returns
Section titled “Returns”boolean
write: (name, value) => string;Write a value as JSON (atomically) → its workspace-relative path.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
value |
unknown |
Returns
Section titled “Returns”string
db: (path) => object;Open a SQLite database file in the workspace (path workspace-relative; the file and
its folder are created when missing) — directly in this routine's process, in WAL mode
with a busy timeout, so it is safe beside Cowork's own readers. Handles close when the
run ends.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
path |
string |
Returns
Section titled “Returns”exec: (sql, params?) => CoworkDbExecResult;One write or DDL statement — a string holding a second statement throws.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
sql |
string |
params? |
unknown[] |
Returns
Section titled “Returns”query: (sql, params?) => CoworkDbQueryResult;One statement's rows. Meant for reads: it does not refuse a write, but exec is the
call for writes.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
sql |
string |
params? |
unknown[] |
Returns
Section titled “Returns”transaction
Section titled “transaction”transaction: <T>(fn) => T;Runs fn atomically: a throw rolls everything back. SYNC-ONLY — an async callback
(or one returning a promise) throws, as an awaited gap would hold the transaction
open across unrelated work.
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
T |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn |
() => T |
Returns
Section titled “Returns”T
error: (name, message) => Error;An Error carrying name, to throw: throw ctx.error("NotConnected", "Paste your token in the sidebar.") — the widget's promise rejects with e.name === "NotConnected" instead of a
message to match. ctx.credential throws NotConnected itself.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
message |
string |
Returns
Section titled “Returns”Error
identity
Section titled “identity”identity: CoworkIdentity;Who this run is for — the signed-in user and their organization, as Cowork saw them
when the run started (frozen). Use it to act on WHO (e.g. stamp an approver). Nobody
signed in: user and organization null.
journal
Section titled “journal”journal: object;Leave a learning / error note for a skill in the skill journal
(source defaults to "routine:
add: (entry) => CoworkJournalEntry;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
entry |
{ kind?: "learning" | "error" | "note"; skill: string; source?: string; text: string; } |
entry.kind? |
"learning" | "error" | "note" |
entry.skill |
string |
entry.source? |
string |
entry.text |
string |
Returns
Section titled “Returns”log: (...parts) => void;A line in the run's log — strings as written, anything else as JSON; console.log
lands there too. It streams while the run is live, and a run that failed or changed
something keeps its last lines in its record.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
...parts |
unknown[] |
Returns
Section titled “Returns”void
notify
Section titled “notify”notify: (n) => Promise<void>;An OS notification from this routine's app — what cowork.notify does in a
widget, and the way to notify while no pane is open (a poll that found new
mail): await ctx.notify({ title: "New email", body: from, tag: "inbox" }).
The desktop app shows it even with its window closed; a browser tab on the
workspace is best effort; only the ACTIVE workspace's show, and nobody showing
it within a minute drops it (the next poll repeats it). Muted or past 6 a
minute: dropped, still resolves. A capability's notifications go to the one
app that uses it (a click opens that app; either one's switch mutes them). A
routine outside an app (.cowork/apps/<name>/) gets BadRequest. One raised by a
run that a notification started (or a routine it called) shows, but starts no routine.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
n |
{ body?: string; tag?: string; title: string; urgent?: boolean; } |
n.body? |
string |
n.tag? |
string |
n.title |
string |
n.urgent? |
boolean |
Returns
Section titled “Returns”Promise<void>
queue: (name) => object;A task queue in this workspace (.cowork/local/queues.db), direct; the same
tasks as cowork queue … and the Tasks view. send creates it; receive takes the
oldest task for as or for anyone (null = none); ack/nack need its receipt —
ack's result and files are the holder's entry (a {path} only from inside the
workspace), review asks the owner, to hands it on. Files: {path}
(workspace-relative or absolute, copied), {name, text} or {name, base64}.
list's q: every word, in what the Tasks view shows of a task.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
Returns
Section titled “Returns”object
ack: (id, receipt, opts?) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
receipt |
string |
opts? |
{ files?: CoworkQueueFileInput[]; result?: string; review?: boolean; to?: string; } |
opts.files? |
CoworkQueueFileInput[] |
opts.result? |
string |
opts.review? |
boolean |
opts.to? |
string |
Returns
Section titled “Returns”approve
Section titled “approve”approve: (id) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
Returns
Section titled “Returns”counts
Section titled “counts”counts: () => Record<CoworkTaskView, number>;Returns
Section titled “Returns”Record<CoworkTaskView, number>
list: (opts?) => CoworkQueueTask[];Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts? |
{ agent?: string; before?: number; limit?: number; q?: string; view?: CoworkTaskView; } |
opts.agent? |
string |
opts.before? |
number |
opts.limit? |
number |
opts.q? |
string |
opts.view? |
CoworkTaskView |
Returns
Section titled “Returns”nack: (id, receipt, opts?) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
receipt |
string |
opts? |
{ delayS?: number; error?: string; } |
opts.delayS? |
number |
opts.error? |
string |
Returns
Section titled “Returns”peek: (id) => | CoworkQueueTask | null;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
Returns
Section titled “Returns”| CoworkQueueTask
| null
receive
Section titled “receive”receive: (opts?) => | CoworkQueueTask & object | null;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
opts? |
{ as?: string; leaseS?: number; mine?: boolean; } |
opts.as? |
string |
opts.leaseS? |
number |
opts.mine? |
boolean |
Returns
Section titled “Returns”| CoworkQueueTask & object
| null
reject
Section titled “reject”reject: (id, comment) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
comment |
string |
Returns
Section titled “Returns”reply: (id, body, opts?) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
body |
string |
opts? |
{ as?: string; files?: CoworkQueueFileInput[]; ref?: string; to?: string | null; } |
opts.as? |
string |
opts.files? |
CoworkQueueFileInput[] |
opts.ref? |
string |
opts.to? |
string | null |
Returns
Section titled “Returns”retry: (id) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
number |
Returns
Section titled “Returns”send: (body, opts?) => CoworkQueueTask;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
body |
string |
opts? |
{ as?: string; delayS?: number; files?: CoworkQueueFileInput[]; meta?: Record<string, unknown>; ref?: string; review?: boolean; subject?: string; to?: string; } |
opts.as? |
string |
opts.delayS? |
number |
opts.files? |
CoworkQueueFileInput[] |
opts.meta? |
Record<string, unknown> |
opts.ref? |
string |
opts.review? |
boolean |
opts.subject? |
string |
opts.to? |
string |
Returns
Section titled “Returns”routines
Section titled “routines”routines: object;Run another routine of this workspace and await its result — an ordinary run (off
switch, a concurrency slot, its own audit record naming this run in
caller.chain). An id your app declares is your app's own routine.
· calls nest two deep: a → b → c runs, c calling another throws RoutineDepth;
a routine already in the chain throws RoutineCycle;
· the nested run never outlives this one (timeoutMs is capped by what is left);
· resolves with its result; a routine that threw rejects with ITS e.name (and
e.runId); a refusal rejects as NotFound, RoutineDisabled or
TooManyRoutines — thrown at once, never waited out.
run: (id, args?, opts?) => Promise<unknown>;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id |
string |
args? |
unknown |
opts? |
{ timeoutMs?: number; } |
opts.timeoutMs? |
number |
Returns
Section titled “Returns”Promise<unknown>
secrets
Section titled “secrets”secrets: object;The signed-in Cowork account's secrets, kept encrypted on this computer (the key in the OS keychain) — one store for every workspace, never synced: get() returns undefined for an unset name; list() returns names only (never values).
Reserved namespace: names under "cowork." are SYSTEM-managed — provisioned by signing in, not writable by apps/routines/the CLI. "cowork.openrouter" is a preprovisioned OpenRouter API key, present ONLY when signed in — base URL https://openrouter.ai/api/v1 (OpenAI-compatible), enough to call OpenRouter's free ":free" models out of the box. Read it like any secret: ctx.secrets.get("cowork.openrouter").
A capability's routines touch only its own family (<name>.* — what they cache, like
a user id) plus reading "cowork.openrouter"; the service it connects to is
ctx.credential. Anything else — and every secret from an APP's routine — throws
NotGranted (an app calls its capability's routines with ctx.routines.run). A package
that declares neither kind nor uses predates capabilities and keeps unrestricted
access until it declares one.
get: (name) => string | undefined;Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
Returns
Section titled “Returns”string | undefined
list: () => string[];The names this routine may read (never values).
Returns
Section titled “Returns”string[]
set: (name, value) => void;Store a secret from inside a routine — a value it caches, a token it minted. THROWS on a reserved "cowork." name or an invalid name (grammar: /^[A-Za-z_][A-Za-z0-9_.-]*$/ — no colons). To forget the connection, ctx.credential.disconnect().
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name |
string |
value |
string |
Returns
Section titled “Returns”void
unchanged
Section titled “unchanged”unchanged: () => void;This run changed nothing — a read, a poll that found nothing. It stays in the
local audit but is not an execution: never reported to a team server, left out of the run
lists (cowork routine runs --unchanged shows it). A run that then throws counts anyway.
Returns
Section titled “Returns”void
workspaceRoot
Section titled “workspaceRoot”workspaceRoot: string;The workspace folder's path. A routine does not run with it as its working directory: resolve workspace files against it.