Skip to content

Private vs workspace apps

Most reads in the App SDK are filtered by what kind of app you are. There are two kinds:

  • Workspace app — installed into, and locked to, a single workspace. The host knows its workspace id. Reads are scoped to that one workspace; cross-workspace requests are rejected.
  • Private (personal) appnot bound to any workspace (e.g. the marketplace, personal tools). Reads span all workspaces the user belongs to, and a few workspace-management methods are only available here.

You can tell which one you're in from hailer.info(): a workspace app has a workspaceId; a private app does not.

What changes, method by method

The host applies the scope on its side, so it's the same call returning different data:

MethodWorkspace appPrivate app
workspace.list()Just the app's workspaceAll the user's workspaces (sorted by name)
workspace.current()The app's workspaceThe user's currently-active workspace
workspace.create(name)Rejected (403)Allowed
workflow.list()Workflows in the app's workspaceWorkflows across all workspaces
workflow.get(id)Scoped to the app's workspaceAny workspace the user can see
team.list()Teams in the app's workspaceTeams across all workspaces
user.get(id)null if the user isn't in the app's workspaceAny user the app can see
user.list()Members of the current workspaceMembers of the current workspace
permission.map({workspaceId})Always the app's workspace; a different workspaceId is rejected (403)All workspaces, or a specific one on request
insight.list()Insights in the app's workspaceInsights in the user's current workspace

team.list() and permission.map() return data keyed by workspace id, so a private app's result can contain several workspaces at once — iterate the keys rather than assuming one.

Practical implications

Don't hard-code a single workspace. In a private app, results are multi-workspace. Read the workspace id off each item (workflows carry a workspaceId; teams/permissions are keyed by it) instead of assuming there's only one.

Guard workspace-management calls. workspace.create() throws in a workspace app. Only offer it when you're a private app:

ts
const { workspaceId } = hailer.info();
const isPrivateApp = !workspaceId;

if (isPrivateApp) {
  const ws = await hailer.workspace.create('New workspace');
}

Don't ask a workspace app about another workspace. permission.map({ workspaceId }) with a different id — and any cross-workspace read — is rejected with a 403 in a workspace app. Pass no workspaceId (or the app's own) and let the host scope it.

Empty results reflect scope. A workspace app returning [] from workflow.list() means there are no workflows in that workspace. Check the app's scope with info().

Next steps

Hailer Developer Documentation