ctx.workspaces
Read and drive workspace state through WorkspaceService — create/rename/close workspaces, manage their folders, and subscribe to a frozen snapshot. (Opening editor tabs lives on ctx.editors, not here.)
ctx.workspaces: WorkspaceServiceExample
import { useServiceState } from "@silo-code/sdk";
// read workspace state reactively in a component
function OpenCount() {
const state = useServiceState(ctx.workspaces);
return <span>{state.open.length} open</span>;
}
// or observe changes imperatively
const sub = ctx.workspaces.subscribe((state) => {
console.log(state.open.length, "open workspaces");
});Methods
On ctx.workspaces. Method names link to the full signature.
| Method | What it does |
|---|---|
getState() | Current frozen WorkspaceState. |
subscribe(listener) | Observe changes; returns a Disposable. |
get(id) | One-shot lookup of a workspace by id (for reactive reads, prefer the state). |
create(input) | Create a workspace from a folder + name. |
createFromFolderPicker() | Show a folder picker, then create. |
rename(id, name) | Rename a workspace. |
reorder(from, to, position) | Reorder workspaces. |
activate(id) | Activate (and reopen if closed). |
close(id) | Soft close — hidden but still saved. |
reopen(id) | Reverse of close. |
delete(id) | Hard delete — permanent removal (also reaps the workspace's terminals). |
addFolder(id, folder) | Add an extra folder to a workspace. |
removeFolder(id, folder) | Remove an extra folder. |
State
The readable state — a frozen WorkspaceState from getState(), subscribe, or useServiceState:
| Property | Type | What it is |
|---|---|---|
all | readonly Workspace[] | every workspace, in user order |
open | readonly Workspace[] | open workspaces (not closed) |
closed | readonly Workspace[] | closed workspaces, most-recent first |
activeId | string | null | id of the active workspace |
hydrated | boolean | true once persisted state has loaded |
Workspace status
Ephemeral status rows below each workspace's path line (adorn verbs — see ADR 0029 / ADR 0030). bindStatus returns an array of rows per workspace (unlike tab bindActivity, which returns a single adornment or null).
Each row may include an Activity (working | ready | warn | error). Omit activity for the neutral gray fallback.
ctx.subscriptions.push(
ctx.workspaces.bindStatus({
id: "my-ext.status",
provide(workspaceId) {
return getRunningTasks(workspaceId).map((t) => ({
id: t.id,
activity: "working",
label: t.name,
startedAt: t.startedAt,
}));
},
}),
);
// Or imperatively:
ctx.workspaces.setStatus(workspaceId, {
id: "one-shot",
activity: "ready",
label: "Ready",
});
ctx.workspaces.clearStatus(workspaceId, "one-shot");| Method | What it does |
|---|---|
setStatus / clearStatus | Imperative rows |
bindStatus | Keep a projection in sync (provide → array) |
registerStatus | Deprecated shim → bindStatus |
getStatus | Imperative + binder rows |
invalidateStatus | Re-query binders |
subscribeStatus | Listen for changes |
Each row is a WorkspaceStatusRow.
Workspace sections
Extensions can mount an arbitrary React component inside each workspace row — below the path line and any status rows. Sections are useful for richer surfaces: interactive cards, agent-status summaries, call indicators, etc.
Return null from your component for workspaces where the section should not appear. This produces no DOM node and no visual gap.
ctx.subscriptions.push(
ctx.workspaces.registerSection({
id: "my-ext.section",
component: ({ workspaceId }) => {
const ws = ctx.workspaces.get(workspaceId);
if (!ws?.terminals.length) return null;
return <MyCard terminals={ws.terminals} />;
},
order: 0, // lower = higher in the stack, default 0
}),
);Multiple providers from different extensions stack vertically in ascending order. Each component is responsible for its own top margin/padding and must use only --silo-* design tokens.
| Method | What it does |
|---|---|
registerSection(provider) | Register a React component to mount in workspace rows. Returns a Disposable. |
subscribeSection(listener) | Subscribe to provider registration changes. Returns a Disposable. |
The provider shape is WorkspaceSectionProvider; component props are WorkspaceSectionProps.
Workspace badges
Inline badges next to the workspace name (same adorn verbs as status).
ctx.subscriptions.push(
ctx.workspaces.bindBadge({
id: "my-ext.badges",
provide(workspaceId) {
const env = getEnv(workspaceId);
if (!env) return [];
return [{ id: "env", text: env.label, color: env.color }];
},
}),
);
ctx.workspaces.setBadge(workspaceId, {
id: "ci",
text: "fail",
color: "#f87171",
});
ctx.workspaces.clearBadge(workspaceId, "ci");| Method | What it does |
|---|---|
setBadge / clearBadge | Imperative badges |
bindBadge | Keep a projection in sync |
registerBadge | Deprecated shim → bindBadge |
getBadges | Imperative + binder badges |
invalidateBadges | Re-query binders |
subscribeBadges | Listen for changes |
Each badge is a WorkspaceBadge.
Workspace property pages
Extensions can contribute a tab to the workspace properties modal — the right place for per-workspace configuration (persistent settings the user adjusts through forms). The modal always shows a tab bar: the built-in General tab (name, folders) first, then registered pages in ascending order.
Persist the page's settings via ctx.storage.workspace, immediately on change — the modal has no Save button. For one-shot actions (refresh, clear) prefer a workspace context-menu item instead; property pages are for configuration.
ctx.subscriptions.push(
ctx.workspaces.registerPropertyPage({
id: "my-ext.properties",
title: "My Extension",
component: ({ ws }) => (
<MySettingsForm
value={readSettings(ws.id)}
onChange={(next) => writeSettings(ws.id, next)}
/>
),
visible: (ws) => isRelevant(ws), // hide the tab where it doesn't apply
}),
);| Method | What it does |
|---|---|
registerPropertyPage(page) | Register a tab in the workspace properties modal. Returns a Disposable. |
The page shape is WorkspacePropertyPage; component props are WorkspacePropertyPageProps.
Types
Pass WorkspaceService.
Related: WorkspaceState · WorkspaceStatusRow · WorkspaceStatusProvider · WorkspaceSectionProvider · WorkspaceSectionProps · WorkspaceBadge · WorkspaceBadgeProvider · WorkspacePropertyPage · WorkspacePropertyPageProps · CreateWorkspaceInput · OpenFileOptions.
See also
Other State members on ctx.