Skip to content

Host settings API

client.hostSettings reads and changes settings the connected device itself exposes — today, the host name and timezone of a Linux system managed by systemd. The provider defines the fields; your app presents them without knowing which operating system is underneath.

Availability

Reading needs the host.settings.read permission, applying needs host.settings.write, and both need a connected workspace whose provider offers the host.settings capability. A provider without remote settings simply reports the capability as absent.

Even with both permissions, individual fields can be read-only: the provider decides, and says why.

Interface

ts
interface RemoteHostSetting {
  binding: string;
  id: string;                    // for example "linux.hostname"
  label: string;
  description: string;
  value: string | null;          // null when the provider could not read it
  revision: string | null;       // pass this back when applying
  editor: "text" | "select";
  choices: string[];             // options for a select editor
  writable: boolean;
  reason: string | null;         // why it is read-only, when it is
}

interface AppHostSettingsAPI {
  read(location: { binding: string }, signal?: AbortSignal): Promise<RemoteHostSetting[]>;
  apply(setting: Pick<RemoteHostSetting, "binding" | "id" | "revision">, value: string, signal?: AbortSignal): Promise<RemoteHostSetting>;
}

apply returns the setting as the provider re-read it afterwards, so the value you display is the one the host actually has — not the one you sent.

Examples

Read what the device offers and build an interface from it:

ts
const env = await client.environment.get();
if (!env.binding || !env.capabilities.includes("host.settings")) return;

for (const setting of await client.hostSettings.read({ binding: env.binding })) {
  addField({
    label: setting.label,
    help: setting.description,
    value: setting.value ?? "",
    kind: setting.editor,             // "text" or "select"
    options: setting.choices,
    disabled: !setting.writable,
    note: setting.writable ? undefined : setting.reason ?? undefined,
  });
}

Apply a change with the revision you read, and show the verified result:

ts
const updated = await client.hostSettings.apply(
  { binding: setting.binding, id: setting.id, revision: setting.revision },
  "europe/sofia",
);
show(`${updated.label} is now ${updated.value}`);

Always confirm with the user before applying — these change the machine, not your app. Read the settings again after a failure: the message tells you when a refresh is required.

Errors

CodeMessageMeaning
invalidSupply the accepted binding and documented setting parameters, including a revision for changes.Missing revision or wrong shape.
unavailableRemote settings are unavailable on this connection.The provider offers no settings.
unavailableNo remote settings source in this workspace.Nothing is bound to that role.
closedThis setting belongs to a previous connection. Refresh settings after accepting the current connection.Stale binding.
busyWait for the previous settings operation to finish.One read and one apply at a time.
abortedThe settings operation ended after cancellation or a connection change. It may have been applied; refresh before retrying.Genuinely uncertain — refresh, do not retry blindly.
failedThe provider's messageFor example a rejected value or a command failure.

Provider messages are worth surfacing verbatim: they explain, for instance, that a change was not confirmed and the host may already have applied it.

Lifecycle and permissions

One read and one apply may be outstanding per window; the window stays busy until a write settles, so the desktop will not quit or disconnect in the middle of a change.

Settings are validated by the provider before anything runs on the host, and applying is verified by reading the value back. A revision mismatch means someone else changed the setting — refresh and review again rather than forcing your value.

This API is about the device. Your app's own preferences belong in storage, which needs no connection.

ShellCanvas documentation