Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ Auto-detection can exist as a convenience, but should be tiered and explainable:

The readiness check should be a clear, single command (e.g. `docker info`) and the UI should show the exact error output when it fails.

### Example: MicroSandbox-backed sandboxes (desktop)

When enabling MicroSandbox-backed sandbox mode, prefer an explicit override for the `msb` binary:

- `OPENWORK_MICROSANDBOX_BIN` (absolute path to `msb`)

This keeps the desktop app predictable on systems where GUI PATH resolution differs from shell PATH.

Default expectations:

1. Honor `OPENWORK_MICROSANDBOX_BIN` if set.
2. Try the process PATH.
3. On macOS, try the login PATH from `/usr/libexec/path_helper`.
4. Fall back to well-known locations like `~/.microsandbox/bin/msb`.

The readiness check should be a clear, single command (for example `msb ls --format json`) and the UI should show the exact error output when it fails. On macOS, MicroSandbox should be treated as Apple Silicon-only. On Linux, it should be treated as requiring hardware virtualization (KVM).

## Minimal use of Tauri
We move most of the functionality to the openwork server which interfaces mostly with FS and proxies to opencode.

Expand Down
17 changes: 16 additions & 1 deletion apps/app/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,13 @@ export default function App() {
? bundlesStore.handleCreateSandboxConfirm
: undefined
}
onConfirmExtraWorker={
isTauriRuntime()
? bundlesStore.handleCreateMicrosandboxConfirm
: undefined
}
workerLabel="Create Docker sandbox"
extraWorkerLabel="Create MicroSandbox"
workerDisabled={(() => {
if (!isTauriRuntime()) return true;
if (workspaceStore.sandboxDoctorBusy?.()) return true;
Expand Down Expand Up @@ -2516,7 +2523,15 @@ export default function App() {
onWorkerRetry={() => {
void workspaceStore.refreshSandboxDoctor?.();
}}
workerSubmitting={workspaceStore.sandboxPreflightBusy?.() ?? false}
workerSubmitting={
(workspaceStore.sandboxPreflightBusy?.() ?? false) &&
workspaceStore.sandboxActiveBackend?.() !== "microsandbox"
}
extraWorkerSubmitting={
((workspaceStore.sandboxPreflightBusy?.() ?? false) ||
(workspaceStore.sandboxCreatePhase?.() ?? "idle") !== "idle") &&
workspaceStore.sandboxActiveBackend?.() === "microsandbox"
}
localDisabled={!isTauriRuntime()}
localDisabledReason={
!isTauriRuntime()
Expand Down
6 changes: 4 additions & 2 deletions apps/app/src/app/bundles/skill-destination-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export default function SkillDestinationModal(props: {
const workspaceBadge = (workspace: WorkspaceInfo) => {
if (
workspace.workspaceType === "remote" &&
(workspace.sandboxBackend === "docker" ||
((workspace.sandboxBackend === "docker" ||
workspace.sandboxBackend === "microsandbox") ||
Boolean(workspace.sandboxRunId?.trim()) ||
Boolean(workspace.sandboxContainerName?.trim()))
) {
Expand Down Expand Up @@ -80,7 +81,8 @@ export default function SkillDestinationModal(props: {

const isSandboxWorkspace = (workspace: WorkspaceInfo) =>
workspace.workspaceType === "remote" &&
(workspace.sandboxBackend === "docker" ||
((workspace.sandboxBackend === "docker" ||
workspace.sandboxBackend === "microsandbox") ||
Boolean(workspace.sandboxRunId?.trim()) ||
Boolean(workspace.sandboxContainerName?.trim()));

Expand Down
19 changes: 18 additions & 1 deletion apps/app/src/app/bundles/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ export function createBundlesStore(options: {
const badge =
workspace.workspaceType === "remote"
? workspace.sandboxBackend === "docker" ||
workspace.sandboxBackend === "microsandbox" ||
Boolean(workspace.sandboxRunId?.trim()) ||
Boolean(workspace.sandboxContainerName?.trim())
? "Sandbox"
Expand Down Expand Up @@ -805,9 +806,14 @@ export function createBundlesStore(options: {
}
};

const handleCreateSandboxConfirm = async (preset: WorkspacePreset, folder: string | null) => {
const handleCreateManagedSandboxConfirm = async (
backend: "docker" | "microsandbox",
preset: WorkspacePreset,
folder: string | null,
) => {
const request = createWorkspaceRequest();
const ok = await options.workspaceStore.createSandboxFlow(
backend,
preset,
folder,
request
Expand Down Expand Up @@ -843,6 +849,16 @@ export function createBundlesStore(options: {
}
};

const handleCreateSandboxConfirm = async (
preset: WorkspacePreset,
folder: string | null,
) => handleCreateManagedSandboxConfirm("docker", preset, folder);

const handleCreateMicrosandboxConfirm = async (
preset: WorkspacePreset,
folder: string | null,
) => handleCreateManagedSandboxConfirm("microsandbox", preset, folder);

return {
queueBundleLink,
openDebugBundleRequest,
Expand All @@ -866,6 +882,7 @@ export function createBundlesStore(options: {
openRemoteConnectFromSkillDestination,
handleCreateWorkspaceConfirm,
handleCreateSandboxConfirm,
handleCreateMicrosandboxConfirm,
dismissUntrustedBundleWarning,
confirmUntrustedBundleWarning,
bundleImportChoice,
Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/app/components/session/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@ export default function SessionSidebar(props: SidebarProps) {
const detailLabel = () => workspaceDetailLabel(group.workspace);
const isSandboxWorkspace = () =>
group.workspace.workspaceType === "remote" &&
(group.workspace.sandboxBackend === "docker" ||
((group.workspace.sandboxBackend === "docker" ||
group.workspace.sandboxBackend === "microsandbox") ||
Boolean(group.workspace.sandboxRunId?.trim()) ||
Boolean(group.workspace.sandboxContainerName?.trim()));
const sessions = () => group.sessions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const workspaceLabel = (workspace: WorkspaceInfo) =>
const workspaceKindLabel = (workspace: WorkspaceInfo) =>
workspace.workspaceType === "remote"
? workspace.sandboxBackend === "docker" ||
workspace.sandboxBackend === "microsandbox" ||
Boolean(workspace.sandboxRunId?.trim()) ||
Boolean(workspace.sandboxContainerName?.trim())
? "Sandbox"
Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/app/components/workspace-chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default function WorkspaceChip(props: {
: props.workspace.path;
const isSandboxWorkspace =
props.workspace.workspaceType === "remote" &&
(props.workspace.sandboxBackend === "docker" ||
((props.workspace.sandboxBackend === "docker" ||
props.workspace.sandboxBackend === "microsandbox") ||
Boolean(props.workspace.sandboxRunId?.trim()) ||
Boolean(props.workspace.sandboxContainerName?.trim()));
const translate = (key: string) => t(key, currentLocale());
Expand Down
Loading
Loading