GlobalStacks logo GlobalStacks Extensions
Open app
Extensions

Building Extensions

Build GlobalStacks extensions with manifest-driven permissions, host viewports, sandboxed iframes, and brokered UI.

Building extensions

Extensions add UI, operations, and configuration surfaces to GlobalStacks without taking over the console runtime. Like Stripe apps, extension UI is authored by the extension but hosted inside GlobalStacks. The console mounts those views in sandboxed iframes, declares what they need in an install-time manifest, and renders them through GlobalStacks-owned bridge and component contracts.

Project shape

A UI-enabled extension repository should keep the extension source, manifest, and package metadata together:

Terminal
extensions/<extension-key>/
  extension.toml
  package.json
  src/
    index.ts
    views/
      Overview.tsx
      Settings.tsx

The extension package imports the SDK, registers exported views, and returns serializable UI nodes. The console owns viewport placement, iframe sandbox policy, theme context, keyboard integration, and the operation bridge. First-party console code should not implement provider-specific configuration screens for extension-owned workflows.

Manifest contract

The manifest is the install-time contract. It identifies the extension, declares the sandbox runtime, lists permission requests with purpose text, and describes where UI should appear.

Terminal
id = "dev.globalstacks.example"
name = "Example Extension"
version = "0.1.0"
distribution = "private"
sandbox_install_compatible = true
runtime = "sandbox"
entrypoint = ["node", "dist/index.js"]

[[permissions]]
permission = "example.resource.read"
purpose = "Show example resources in the console."
scope = "install"

[[ui.views]]
viewport = "globalstacks.console.extension.detail"
component = "ExampleOverview"
root = "ContextView"

[[ui.views]]
viewport = "globalstacks.console.extension.settings"
component = "ExampleSettings"
root = "SettingsView"

[ui.content_security_policy]
"connect-src" = []
"image-src" = []
purpose = "This extension does not require browser network access."

Viewports

Viewports are stable host placement contracts. Extensions request a viewport; the console decides when to mount the view and what context to provide.

  • globalstacks.console.extension.detail
  • globalstacks.console.extension.settings
  • globalstacks.console.stack.detail
  • globalstacks.console.project.detail
  • globalstacks.console.host.detail
  • globalstacks.console.full_page
  • globalstacks.console.command_palette

Iframe lifecycle

Extension UI is embedded only for extension surfaces. First-party console pages continue to render directly in the console application.

When an extension viewport is visible, the console creates a sandboxed iframe for the shared GlobalStacks extension renderer, passes the selected view and context, and receives serialized UI events through the bridge. The iframe can stay warm across view changes or be torn down when the console needs to reclaim resources. The console only mounts installed extension UI after the extension install has reconciled its runtime sandbox.

The iframe boundary means extension UI code cannot reach the parent console DOM, storage, routes, credentials, host APIs, or network APIs. The iframe shell disables direct API connections; all privileged work must go through declared permissions and brokered operations.

Runtime extension code runs separately from the trusted console in the configured extension sandbox, such as a container-backed sandbox. UI form submissions and actions cross the bridge as typed operations, then the extension runtime performs only the manifest-declared broker work. For host-facing operations, the runtime must call typed GlobalStacks/agent APIs; it must not shell into hosts or invoke agent CLI commands through a terminal bridge.

Extension manifests default to runtime = "sandbox" when no runtime is declared. Sandbox-runtime extensions must publish an immutable runtime artifact_ref; installs fail closed until the runtime image can be resolved and reconciled into an extension sandbox.

Install progress appears on the Extensions page, the install review modal, the Builds page, and blueprint detail pages. The lifecycle shows whether the runtime image has been built and published, whether install consent has been granted, whether the runtime sandbox has reconciled, and whether the configuration UI is ready. When a sandbox runtime image is missing and the manifest declares build source metadata, the extension card can create a first-class runtime build directly and shows the resulting build status and progress. Clicking a blueprint or its artifact opens the blueprint detail page with artifact metadata and any related build status.

Extension runtime builds use typed host-agent build requests, source-control repository connections, and short-lived internal registry push credentials. BuildKit runs inside the builder sandbox through the sandbox-agent socket. The builder sandbox is created from the globalstacks-buildkit-builder blueprint, which is seeded from the digest-pinned GLOBALSTACKS_BUILDKIT_BUILDER_IMAGE artifact. Declared build egress is separate from runtime egress and is enforced by the host-agent sandbox egress proxy for the selected build runtime.

System and tenant ownership

GlobalStacks-owned extension supply chain work belongs to the system organization. The system organization owns first-party marketplace listings, extension versioning, sandbox build blueprints, extension runtime builds, and shared digest-pinned artifacts that user tenants can consume.

User tenants do not build or own first-party extension artifacts during install. They review the published manifest, grant tenant-scoped consent, select authorized clusters, and run the installed extension runtime sandbox in their own infrastructure from the prebuilt artifact. Sandbox-backed extension installs fail closed when no immutable runtime artifact_ref is published, or when the install request omits cluster-scoped consent.

The install consent record is server-derived from the current manifest. It stores required permissions, runtime egress, build egress, build runtime, and build source metadata so a crafted install payload cannot reduce or skip the consented requirements.

Root views

Every UI surface should start with a root view component:

  • ContextView for contextual panels and extension detail views.
  • SettingsView for install or account-level settings.
  • FocusView for task flows that need focused attention.
  • SignInView for external account connection and onboarding.
  • FullPageView for dense extension pages.

UI authoring

Extension views return SDK components. Props and children must be serializable, and event handlers are registered out-of-band through the bridge.

Terminal
import {
  Button,
  ContextView,
  DataGrid,
  Stack,
  Text,
  type UINode,
  type ViewContext,
} from "@globalstacks/ui-extension-sdk";

export function ExampleOverview(context: ViewContext): UINode {
  return (
    <ContextView title="Example">
      <Stack gap="md">
        <Text tone="muted">Resources visible to this extension.</Text>
        <DataGrid
          columns={[
            { id: "name", header: "Name", sortable: true },
            { id: "status", header: "Status", type: "status", pinned: "right" },
          ]}
          rows={[
            { id: "primary", name: "Primary resource", status: "ready" },
          ]}
          rowActions={[{ id: "open", label: "Open", variant: "secondary" }]}
          onAction={() => undefined}
        />
        <Button onClick={() => undefined}>Refresh</Button>
      </Stack>
    </ContextView>
  );
}

Runtime boundaries

Extension UI should not assume direct access to console internals, tenant data, browser network origins, or host resources. Those capabilities must be declared and mediated:

  • Use manifest permissions for operations and data access.
  • Use UI CSP fields for browser network and image origins.
  • Use bridge events for actions, navigation, refreshes, and operation invocation.
  • Let the iframe renderer and parent console bridge own visual treatment, accessibility, layout, and operation dispatch.

Next steps

  • Use the design system page to align extension screens with the current console UI.
  • Use the style extension UI page when applying tokens, layout props, spacing, sizing, and preset component styles.
  • Use the component library page to choose supported UI primitives.
  • Keep manifests explicit; purpose text is user-facing install consent copy.
  • Add tests that render extension views and assert the serialized node tree.