Developer

Places API

Read workspace places from your custom resource.

The Places API provides read-only access to places (workspaces/canvases) in a project. Use it to list all places or filter by project.

Capability required: places:read

Frontend (iframe)

import { createResourceClient } from "@rightplace/sdk";

const rp = createResourceClient();
await rp.ready();

// List places in a specific project
const places = await rp.places.list("project-id-123");
// -> [{ id: "p1", title: "Homepage", slug: "homepage", projectId: "project-id-123", ... }]

// List all places across all projects
const allPlaces = await rp.places.list();

Backend (Node.js)

import { createResourceServer } from "@rightplace/sdk/server";

const server = createResourceServer({
  methods: {
    getPlaces: async (_params, { rp }) => {
      return await rp.places.list("project-id");
    },
  },
});

server.start();

MCP

Every rp.places.* method is exposed via the CallRegistry hook with the rightplace_places_ prefix. Reads require places:read; writes require places:write.

ToolPurposePermission
rightplace_places_listTabsAll tabs in a placeplaces:read
rightplace_places_listPanesAll panes in a layoutplaces:read
rightplace_places_loadLayoutPersisted layout treeplaces:read
rightplace_places_getActiveActive place + projectplaces:read
rightplace_places_getFocusedPaneFocused pane + tabplaces:read
rightplace_places_listOpenTabsTabs in the currently-active placeplaces:read
rightplace_places_openTabOpen a new tabplaces:write
rightplace_places_openResourceOpen a user resource as a tabplaces:write
rightplace_places_openToolOpen a project-level tool (terminal / browser / etc.)places:write
rightplace_places_selectTabFocus an existing tabplaces:write
rightplace_places_closeTabClose a tabplaces:write

RobinPath Bridge

# What is the user looking at right now?
rightplace.places_getActive into $active
rightplace.places_listOpenTabs into $tabs
log "active place:" $active.placeId "tabs:" $tabs.length

# Focus a specific tab
rightplace.places_selectTab {tabId: $tabs[0].id}

# Open a resource in a new tab (current pane, current place)
rightplace.places_openResource {resourceId: "res_docs_readme"} into $opened
log "opened tab:" $opened.tabId

# Open a project tool
rightplace.places_openTool {tool: "terminal"}

# Or use the generic hook dispatcher - identical behavior, different entrypoint
rightplace.hook "res_docs_readme" "places.openResource" {resourceId: "res_docs_readme"}

API Reference

rp.places.list(projectId?)

Returns places, optionally filtered by project.

ParameterTypeDescription
projectIdstringOptional project filter
ReturnsPromise<PlaceInfo[]>List of places

PlaceInfo

FieldTypeDescription
idstringPlace ID
titlestringPlace title
slugstringURL-safe slug
projectIdstringOwning project ID
createdAtnumberUnix timestamp (seconds)
updatedAtnumberUnix timestamp (seconds)

Manifest Configuration

{
  "capabilities": [
    "places:read"
  ]
}

Notes

  • This API is read-only. Resources cannot create, update, or delete places.
  • The canvas data is not exposed through this API for security and performance reasons.

Listing tabs and panes

All read methods require places:read.

rp.places.listTabs({ placeId, windowNum? })

Returns every tab in the place’s persisted layout. windowNum defaults to "1".

const { tabs } = await rp.places.listTabs({ placeId: "place-123" });
// tabs: [{ id, type, path, title, pinned, paneId, placeId, projectId }, ...]

rp.places.listPanes({ placeId, windowNum? })

Returns { id, tabIds, activeTabId } for every pane.

rp.places.loadLayout({ placeId, windowNum? })

Returns the full layout tree (typed), or null if no layout is saved.

Active state

All require places:read.

rp.places.getActive({ windowLabel? })

“What place is the user on?” - returns { placeId, projectId }. Defaults to the current window.

rp.places.getFocusedPane({ windowLabel? })

Returns { placeId, paneId, activeTabId } for the focused pane.

rp.places.listOpenTabs({ windowLabel? })

Convenience: tabs in the currently-active place. Equivalent to getActive + listTabs.

All require places:write.

rp.places.openTab({ placeId?, paneId?, type, resourceId?, path? })

Open a new tab. Defaults: active place, focused pane. If a tab with the same path already exists, it’s focused instead of duplicating. Returns { tabId, paneId }.

rp.places.openResource({ resourceId, path?, placeId?, paneId? })

Open a user resource (docs, WordPress site, spreadsheet, etc.) as a tab. Returns { tabId, paneId }.

rp.places.openTool({ tool, projectId?, placeId?, paneId? })

Open a project-level tool. tool is one of:

ToolDescription
terminalShell/terminal
browserIn-app web browser
gitGit status / diff view
filesFile & media explorer
editorCode editor
imageeditorImage editor
html_playgroundHTML scratch pad
relay_testRelay Test dev tool (dev mode only)
hooks_testHooks Test dev tool (dev mode only)

rp.places.selectTab({ tabId, placeId?, windowLabel? })

Focus an already-open tab. Returns { tabId, paneId }.

rp.places.closeTab({ tabId, placeId?, windowLabel? })

Close a tab. Refuses to close pinned tabs. Returns { closed, reason? }.

Error cases

ErrorWhen
place not foundplaceId doesn’t exist
tab not found: <id>tabId isn’t in the resolved place’s layout
navigate timeout after 5sFrontend didn’t acknowledge within 5s (no window mounted?)
no active placeNavigation needs an active place; the user isn’t on one yet
tab is pinnedcloseTab called on a pinned tab

Manifest (full)

{
  "capabilities": ["places:read", "places:write"]
}