OpenCode V2 integration
The single @runkids/figlens npm package exposes an OpenCode server entry, ./tui and ./rpc, alongside its CLI, Pi and OMP entries. The root stays CommonJS for the CLI; opencode/ has its own module boundary. Local acceptance targets OpenCode 2.2.0. Other OpenCode generations are not covered.
Install the package in OpenCode V2:
opencode plugin add @runkids/figlens
For a local candidate, use the unpacked package directory as a file:// URL. The package export lets the host load server and TUI entries separately. No other host SDK is imported by these entries.
Use /figlens help, or ask OpenCode to build a screen from a saved .fig. The shortcuts are open, preview, plan, yolo, map, frame, status, review and close. Plan authorizes a plan only; yolo authorizes implementation within the requested scope, then cleans up only its own plan, scratch exports and processes. Dispatch is not proof of model completion. Native TUI review shows evidence, edits all four target fields, resolves conflicts and confirms approval; noninteractive clients leave proposals pending. There is no model approval tool.
The server registers the shared skill and supplies a local figlensmcp MCP configuration only when neither a figlensmcp nor a figlens configuration exists; a user server under either key is used as configured. The managed key differs from figlens because OpenCode drops an MCP server whose name collides with the plugin's figlens_* tools. It preserves disabled, remote and local user overrides. Overrides whose version/snapshot cannot be verified block MCP-dependent shortcuts, while explicit local preview, frame selection, mappings and review remain available. When that user server is disabled, or is named figlens (which OpenCode drops), the plugin registers figlens_index, figlens_jobs, figlens_search, figlens_usages, figlens_diff, figlens_changes, figlens_watch, figlens_inspect and figlens_models, which run the same CLI commands, so the search flow below still works; the managed server or an enabled override serves those tools itself, so they are not registered twice. The managed default uses the same launcher and project directory as local operations; FIGLENS_BIN selects both paths. OpenCode is a Bun-built binary, so the bundled Node launcher runs with the node on PATH (Node 18 or later); FIGLENS_BIN bypasses it.
Searching a design. Ask OpenCode to find copy or a screen in a .fig: it searches the file directly and stores nothing. For repeated searches, ask it to enable an index for that design and a scope (for example "enable an index for ./design.fig, whole file"). The agent then calls index prepare with the file and scope, which creates a local workspace in the figlens state directory with no setup step, polls jobs until the build succeeds, and from then on searches the published index by workspaceId and node set to the chosen scope and opens results with inspect, also after a restart or from another host. Connecting, listing tools and ordinary searches create no database. reset and replaceUnavailable additionally ask OpenCode's figlens_index permission (resource reset or replace_unavailable) on both paths, so a session rule such as { "action": "figlens_index", "resource": "reset", "effect": "deny" } blocks them while preparing and searching stay unprompted; the CLI path also asks bash permission for each command as before and read on the design's requested and real path for search, inspect, prepare, add and relocate (for a workspace search, refresh or rebuild, on the registered designs index status reports, narrowed by sourceId), refuses a gs:// design, whose download cache it cannot authorize (the MCP server reads those), runs builds until their jobs finish without the command timeout, and before a write it runs the read-only index status and asks edit permission on the workspace directory and the lock file beside it that the binary reports (the state root while none exists) plus the config root; a prepare or reset that repairs a workspace whose status fails asks it for the place and lock file the failure reports; jobs cancel asks it for the job's workspace, and recreation for the new storage and the config root.
Finding usages. Ask OpenCode where a component, variable, style or image is used: the agent calls the MCP usages tool with the exact layer or resource id, on the .fig directly (stateless) or, once an index is enabled, by workspaceId, the result's sourceId and the prepared scope; it never prepares, widens or resets an index for it. For a library component, style or variable, it passes library {kind, namespace, key}, taken from the library field of an outgoing usages result on a layer that uses it, with workspaceId instead: the layers in every visible prepared source whose cached copy uses it, with the definition left unresolved. Results carry exact refs, a snapshotId and coverage; a hidden-layer exclusion or a source that changed is reported, not read as "unused". On the CLI path figlens_usages asks bash permission and read on the design (for a workspace, on the registered designs, narrowed by sourceId), as figlens_search does.
Following changes. Ask OpenCode to follow a design's changes, which opts in to that scope's index and history: the agent prepares the scope when no index covers it, then calls index track with the workspace and the scope, which builds a baseline as an index rebuild does, then subscribes with watch subscribe, reads changes with that subscriptionId and acknowledges each page it handled with watch ack; watch unsubscribe stops following, and untrack, only when asked, stops recording for everyone and keeps the history. watch subscribe with sources (visible or up to 10 sourceIds) instead of sourceId saves a search, or with library a library item's uses, over that fixed set; removing a member disables it, so unsubscribe and subscribe again. A tracking entry with refreshRequired means the file changed since its last build and index refresh records the change; an empty page never proves the file unchanged. None of these asks figlens_index. On the CLI path figlens_changes asks read on the registered designs as a workspace search does, track asks it as rebuild does and runs until its baseline job finishes, track and untrack ask edit as any index write does, and every figlens_watch action but list, status and start asks edit on the workspace directory and its lock file, a saved query's or library question's subscribe and evaluate also asking read on the designs they search (a subscribe over listed sources only those designs; with a subscriptionId, evaluate and figlens_changes ask only that subscription's designs, as watch list names them, or every design when it is not listed). To have saves picked up without index refresh, figlens_watch start holds a lease on the tracked scope for this session (it asks read on every registered design, since the shared runner also evaluates saved questions over other designs, and edit on the workspace, then runs figlens watch run as a child it owns); a retry with the same requestId returns this session's lease without a second child, stop ends only a lease this session started, deleting the session or unloading the plugin ends them all and waits for those children, the shared runner is never signalled, and status is read-only. Before each prompt the CLI path checks the subscriptions and consumers this session subscribed to or acknowledged with figlens_watch, through figlens_changes with its permissions, four per prompt one at a time under one 4 s deadline, and adds what it found to that prompt's system context as data; it never acks. They are held in memory, so after an OpenCode restart a session is checked again from its next subscribe or ack. Through an MCP server the session only gets a reminder to read changes itself, because the plugin cannot see that server's --root folders.
Searching by meaning. Search by meaning or across languages needs an optional local model profile that you download yourself; figlens never downloads one. Ask OpenCode to list or check it: the agent calls the MCP models tool with list or status, then configure with the profile and the folder you downloaded, and searches with mode semantic or hybrid. Without a profile semantic is mode_unavailable and hybrid answers with text results. configure and remove change only the profile record under the figlens config folder; remove keeps the model files. On the CLI path, figlens_models list and status ask only bash; configure also asks read on the folder and each pinned file, then edit on the config folder the binary reports, and runs only the figlens-embed shipped beside figlens; remove asks edit on that folder. figlens_index embed, which stores a workspace's model layer for workspace semantic search, asks read on the sources it embeds and edit on the workspace, as a refresh does.
Searching by image. Ask OpenCode to enable visual indexing for the design and scope: the agent calls index with action visual on the prepared scope and polls jobs. It then searches by workspaceId with an authorized local PNG in image, or an exact result reference in imageRef, and optional pixel crop; adding text uses mode hybrid. Hash matching works without a model; optional siglip-base configuration through models adds broader visual similarity. Query images are never stored, and similarity does not prove component identity. The live viewer offers the same image, crop and mode controls. On the CLI path figlens_search asks read on the query PNG as well as the registered designs.
Comparing revisions. Ask OpenCode what changed between two saved copies of a design: the agent calls the MCP diff tool with old and file (local paths) and pages with nextCursor. Layers match by exact id and type only; unknown means a side stopped or left that layer unexpanded, not that it was removed. It reads both files and writes nothing. On the CLI path, figlens_diff asks bash permission and read on old, then on file, before it runs.
Indexes go to the figlens state directory, or to a location an earlier --storage prepare remembered, with no configuration. A new custom location is a filesystem choice: the managed MCP server refuses it, because it starts without --storage-root. To use one over MCP, configure your own figlensmcp local server with ["<figlens>", "mcp", "--storage-root", "/absolute/dir"] and reload; OpenCode then treats it as a user override, as above. On the CLI path, a storage argument asks edit permission on that directory and its state directory. Every CLI-path edit ask also covers the real path a symlink on the way points to, since the binary writes there.
Server operations validate session/project ownership and request read/edit/bash permissions before side effects. Authenticated host clients are trusted: RPC does not prove that a human made the call. UI confirmation is a mapping decision, not a sandbox against other authenticated clients. Read/write errors, cancellation, stale evidence and writer contention remain errors.
Viewer URLs and design paths belong to the server machine. Reference attachments carry PNG bytes through the host file-content format; a textual path is not an image. Each session owns its viewer; deleting a session, reloading or unloading the plugin closes owned viewers. Client disconnect alone does not delete a durable session, so use /figlens close when finished. The adapter creates no tunnel.
Shared mapping files retain Pi's schema and human notes. See Pi for the underlying workflow and integration acceptance for source-checkout checks.
This page is built from opencode/README.md in the repository.