watch
Starts and manages leases on tracked Figma scopes, follows revisions or saved searches, and acknowledges change checkpoints so agents can read updates without an index call.
Instructions
Watching tracked scopes and change-tracking consumers. start: this server holds a lease on tracked scope of one source (sourceId when the workspace has several) and the workspace's shared runner refreshes it on each save, so changes shows new revisions without an index call; the server renews its leases every 10 s and ends them when it exits, and an unrenewed lease ends after 30 s. A requestId replays this server's live lease and reports an ended one as ended (untracked when its scope was untracked or retracked since), never restarting it, for 1 h after the end among the newest 1024 ended leases; past that it is unknown and starts a new lease. A requestId of a lease another running process holds is refused. stop ends one lease this server holds (leaseId). status lists the workspace's leases and runner, read-only. ack moves consumer's checkpoint for these filters (sourceId, scope), or a subscription's own (subscriptionId), forward to cursor, the nextCursor of the last changes page it handled with the same filters; an older or equal cursor normally leaves it, so a retry is safe. A cursor issued before retention deleted revisions it had not passed is event_gap, writing nothing: follow its recovery. A current recovery cursor before a checkpoint that is behind such a deletion moves the checkpoint back to it, so the kept revisions replay. Replies with advanced, true only when the checkpoint moved forward, and the checkpoint now held, which is authoritative. subscribe follows one source, scope or exact node (node: a layer id that must name one layer kind in the published index, else target_missing or identity_uncertain, never a same-name layer) from its newest visible revision; a repeat returns the same subscription; owner marks it temporary for that task. subscribe with query (and type) saves a workspace search of one source's scope (default 0:0) and stores its first evaluation of the top 50; evaluate stores a newer one after a publication, and a watch lease on that scope makes its runner store it unasked; changes with its subscriptionId reads the stored evaluations (causes such as source_changed only for new file bytes or index_rebuilt; enteredTopK and leftTopK are exact sourceId/snapshotId/nodeId refs in the new and old snapshot, rankChanged the new snapshot's refs with from and to positions, null when rankComparable is false, all within the top-50 window, not the whole result set; nodes compare by sourceId, which relocate keeps; total only when the search counted every hit) and reports evaluation pending with an evaluate step, never computing one; an evaluation past 128 KiB is unavailable evaluation_too_large, nothing stored. sources (instead of sourceId) saves the search, or a library question (library), over a fixed set: visible resolves once to the sources this caller sees now, or a comma-separated list, at most 10, returned sorted in subscription.sources; it never gains a source added later. A member's publication evaluates it (its runner too); causes source_changed names members with new bytes in delta.changedSourceIds, corpus_changed a member's relocation or publication, or for a ranked search of several members their shared statistics; refs carry their sourceId and snapshot. A library question lists up to 50 uses with definitionMatch against the definition, followed by its exact nodeId in its source's current snapshot (delta.definitionMatchChanged); coverage.transitive is not_followed: a definition's own library dependencies are never traversed, and delta.notFollowedSourceIds names changed members that hold no use and are not the definition's source, whose dependent uses may be stale. A caller who cannot see every member reads the subscription as unknown; removing a member source disables it (state disabled, disabled.reason source_removed, evaluations deleted; a damaged stored set reads disabled with sources_unreadable): unsubscribe, then subscribe again. list pages the visible subscriptions with their state (subscriptionId: only that one, empty when unknown to the caller). unsubscribe removes one subscription and its checkpoint (or, with owner, that owner's temporary ones); forget removes a consumer's raw checkpoint views. Neither untracks or deletes history. A consumer holds at most 64 subscriptions and checkpoints, a workspace 4096: past that, workspace_busy names list, unsubscribe and forget; nothing is evicted.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"action": "<action>",
"workspaceId": "<workspaceId>"
},
"name": "watch"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| node | No | subscribe: follow this exact layer | |
| type | No | subscribe with query: only these node types, comma-separated, as search takes them | |
| after | No | list: the next of the previous page | |
| owner | No | subscribe: a task-owned temporary subscription; unsubscribe (with consumer): remove that owner's temporary ones | |
| query | No | subscribe: save this workspace search of the scope instead of following revisions | |
| scope | No | start: the tracked scope to watch; ack: the scope filter of that changes call; subscribe: only this scope; forget: only its views | |
| action | Yes | start, stop, status, ack, subscribe, evaluate, list, unsubscribe or forget | |
| cursor | No | ack: nextCursor from changes with the same filters | |
| leaseId | No | stop: the lease to end | |
| library | No | subscribe: save this library question over sources (or sourceId) instead of a search: {kind, namespace, key} and optional definition {sourceId, snapshotId, nodeId}, an exact ref to the definition's current published snapshot in one of the sources | |
| sources | No | subscribe with query or library, instead of sourceId: a fixed set, visible (the sources you see now) or comma-separated sourceIds, at most 10 | |
| storage | No | absolute custom storage directory, only for a workspace kept outside the default storage; must be under the server's --storage-root | |
| consumer | No | the consumer's name, 1-128 bytes: ack without subscriptionId, subscribe and forget need it; list narrows to it | |
| sourceId | No | start: the source to watch; ack: the sourceId filter of that changes call; subscribe: the source to follow; forget: only its views; evaluate takes none (it evaluates the subscription's own source) | |
| requestId | No | start: replays this request's lease | |
| workspaceId | Yes | ws_... from the index tool | |
| subscriptionId | No | ack, evaluate or unsubscribe this subscription; list reads only it |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| next | No | list: pass as after for the next page | |
| scope | No | start: the leased scope | |
| state | No | start, stop: active, or ended with a reason | |
| leases | No | status: leaseId, sourceId, scope, state (active, unauthorized, untracked, expired or ended, with reason), expiresAtMs, mine; live leases first, then the newest ended ones | |
| reason | No | start, stop: why an ended lease ended (stopped, released, expired, start_failed, reset, source_removed) | |
| runner | No | start, status: the workspace's runner: state running, stopping, stopped or unknown; placement independent, or in_host_job when a Windows job object kept it inside the host and it ends with that job | |
| created | No | subscribe: false when the same subscription already existed | |
| leaseId | No | start, stop: the lease | |
| removed | No | unsubscribe, forget: rows removed | |
| advanced | No | ack: true only when the visible checkpoint moved forward | |
| consumer | No | ||
| sourceId | No | start: the leased source | |
| tracking | No | subscribe: the followed scopes' tracking state | |
| truncated | No | status: true when older ended leases are left out | |
| checkpoint | No | ack, subscribe: a cursor at the checkpoint now held; null when retention deleted that revision | |
| evaluation | No | subscribe with query or library, evaluate: state evaluated (evaluationId, causes, delta), current, pending (reason, nextSteps), unavailable (reason such as query_changed, search_failed or evaluation_too_large, nextSteps) or disabled (nextSteps) | |
| expiresAtMs | No | start: when the lease ends unless renewed | |
| workspaceId | Yes | ||
| renewEveryMs | No | start: how often the holder renews; MCP renews for you | |
| subscription | No | subscribe: subscriptionId, consumer, sourceId (null for a set), sources, scope, kind (source, scope, node or query), node, nodeKind, query, types, library, definition, topK, state (active, target_missing, identity_uncertain or disabled), disabled, lifetime (durable or temporary), filterVersion | |
| subscriptions | No | list: one page, as subscription | |
| subscriptionId | No | ack of a subscription | |
| initialPosition | No | subscribe: tail (the newest revision it can see), initial_evaluation (a query, before its first evaluation) or existing | |
| subscriptionIds | No | unsubscribe: the removed subscriptions' ids | |
| keptUnknownOwnership | No | forget: views written before their sources were recorded, kept because this caller does not see every source |