Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
363 lines
11 KiB
Markdown
363 lines
11 KiB
Markdown
# Workbench Node Lifecycle
|
|
|
|
This document describes the lifecycle model for shared Workbench nodes.
|
|
|
|
The goal is to keep `@tutti-os/workbench-surface` usable by Tutti desktop and
|
|
TSH without turning Workbench into a second business core.
|
|
|
|
## Ownership Model
|
|
|
|
Workbench owns node shell presentation:
|
|
|
|
- node shell creation, removal, focus, drag, resize, snap, and minimize mechanics
|
|
- frame, display mode, restore frame, minimized state, and stack order
|
|
- generic dock and window chrome mechanics
|
|
- snapshot persistence for shell presentation state
|
|
|
|
Host code owns business state:
|
|
|
|
- whether a business instance exists
|
|
- how a business instance is created, reused, closed, or restored
|
|
- node body data such as terminal cwd, exit code, browser runtime URL, agent
|
|
session status, workspace tree state, or task progress
|
|
- business persistence and external runtime subscriptions
|
|
|
|
Workbench may receive stable identity metadata for a node shell, but it must not
|
|
become the durable store for business payloads.
|
|
|
|
## Core Concepts
|
|
|
|
The Workbench host interface should separate five concepts that were previously
|
|
easy to blur together:
|
|
|
|
- node definition
|
|
- projected node presence
|
|
- launch request
|
|
- activation
|
|
- snapshot contract
|
|
|
|
### Node Definition
|
|
|
|
A node definition describes how a node type renders and behaves at the shell
|
|
level.
|
|
|
|
It answers: "Given a node shell of this type, how should Workbench render it?"
|
|
|
|
Examples:
|
|
|
|
- `workspace-files`
|
|
- `browser`
|
|
- `terminal`
|
|
- `agent`
|
|
|
|
Node definitions may include:
|
|
|
|
- `typeId`
|
|
- default title and frame
|
|
- body and header renderers
|
|
- shell capabilities such as closable, minimizable, or fullscreenable
|
|
|
|
Node definitions must not own host business state or host-specific transport.
|
|
|
|
Dock presentation and grouping should be modeled separately at the host level.
|
|
See [Workbench Dock Model](./workbench-dock-model.md).
|
|
|
|
### Projected Node Presence
|
|
|
|
Projected node presence is a declarative input from the host into Workbench.
|
|
|
|
It answers: "Which host-owned business instances should currently have a
|
|
Workbench shell?"
|
|
|
|
This is for nodes whose presence is owned by host or runtime facts, such as:
|
|
|
|
- terminal sessions that already exist in a runtime
|
|
- agent sessions created by a host service
|
|
- other host-owned long-lived sessions whose UI should be projected into the
|
|
Workbench
|
|
|
|
Illustrative shape:
|
|
|
|
```ts
|
|
export interface WorkbenchProjectedNode {
|
|
typeId: string;
|
|
instanceId: string;
|
|
instanceKey?: string | null;
|
|
title: string;
|
|
defaultFrame?: WorkbenchFrame;
|
|
subject?: {
|
|
type: string;
|
|
id: string;
|
|
};
|
|
}
|
|
```
|
|
|
|
Semantics:
|
|
|
|
- when the host projects a node, Workbench reconciles a shell into current
|
|
Workbench state
|
|
- when a projected node has the same stable shell identity as a snapshot node,
|
|
Workbench restores presentation state from the snapshot
|
|
- when a projected node is no longer present in the host input, Workbench removes
|
|
the shell by default
|
|
- projected node disappearance is not a business close policy; hosts that want
|
|
an ended session to remain visible should keep projecting it and expose the
|
|
ended state through host-owned external state
|
|
|
|
Projected presence should be reconciled in the Workbench host/session layer, not
|
|
in the lower-level reducer. The reducer should remain a pure shell state machine
|
|
for window mechanics.
|
|
|
|
Projected node `subject` is live lookup metadata. It should not be persisted in
|
|
the Workbench snapshot unless it later becomes a deliberately minimal shell
|
|
identity field. The default position is to keep it out of snapshots.
|
|
|
|
### Launch Request
|
|
|
|
A launch request is a command from Workbench or host UI asking the host to create
|
|
or resolve a business instance.
|
|
|
|
It answers: "The user or shell wants to open this kind of node; host, which
|
|
business instance should back it?"
|
|
|
|
This keeps "create or reuse an instance" as an explicit host decision instead
|
|
of folding it into a catch-all shell command.
|
|
|
|
Illustrative shape:
|
|
|
|
```ts
|
|
export interface WorkbenchLaunchRequest {
|
|
typeId: string;
|
|
reason: "dock" | "command" | "shortcut" | "host";
|
|
}
|
|
|
|
export interface WorkbenchLaunchResult {
|
|
typeId: string;
|
|
instanceId: string;
|
|
instanceKey?: string | null;
|
|
title?: string;
|
|
defaultFrame?: WorkbenchFrame;
|
|
activation?: WorkbenchActivation;
|
|
}
|
|
```
|
|
|
|
Launch requests may be asynchronous.
|
|
|
|
This supports flows such as:
|
|
|
|
```text
|
|
User clicks Terminal in the dock
|
|
-> Workbench sends a launch request
|
|
-> host creates or reuses a terminal session
|
|
-> host returns stable shell identity
|
|
-> Workbench opens or focuses the shell
|
|
```
|
|
|
|
Workbench should not infer business creation policy. The host decides whether a
|
|
launch creates a new instance, reuses an existing instance, fails, or maps to an
|
|
already projected instance.
|
|
|
|
### Activation
|
|
|
|
Activation is a one-shot business action delivered to an existing node shell.
|
|
|
|
It answers: "This node already exists; ask it to do this one thing."
|
|
|
|
Examples:
|
|
|
|
- reveal a path in the files node
|
|
- open a URL in a browser node
|
|
- focus a pane inside a terminal node
|
|
- jump to a message in an agent node
|
|
|
|
Illustrative shape:
|
|
|
|
```ts
|
|
export interface WorkbenchActivation {
|
|
type: string;
|
|
payload?: unknown;
|
|
sequence: number;
|
|
}
|
|
```
|
|
|
|
Activation does not decide whether a node exists. If an action requires a node
|
|
to exist first, the caller should use launch or projected presence to obtain a
|
|
shell, then deliver activation.
|
|
|
|
Activation targets may be addressed by concrete shell node id, or by
|
|
`typeId` plus `instanceId`. Single-instance nodes may also be addressed by
|
|
`typeId` alone. Multi-instance nodes require an explicit shell id or instance
|
|
id to avoid ambiguous delivery.
|
|
|
|
Activation payloads are transient and must not be written to the Workbench
|
|
snapshot.
|
|
|
|
## Snapshot Rules
|
|
|
|
Workbench snapshots store shell presentation state only.
|
|
|
|
Snapshot purity is a P0 architecture requirement. It should be enforced by a
|
|
package-level sanitizer or validator before host snapshots are persisted.
|
|
|
|
Allowed snapshot data:
|
|
|
|
- node shell id
|
|
- node kind or type id
|
|
- title
|
|
- frame
|
|
- display mode
|
|
- restore frame
|
|
- minimized state
|
|
- node stack
|
|
- minimal shell identity metadata such as `typeId`, `instanceId`, and
|
|
`instanceKey`
|
|
- projected shell marker such as `isProjected`
|
|
|
|
Disallowed snapshot data:
|
|
|
|
- terminal cwd
|
|
- terminal process status or exit code
|
|
- browser runtime URL or page state unless deliberately modeled as shell
|
|
identity
|
|
- agent session status, messages, or active task state
|
|
- workspace tree contents
|
|
- launch payloads
|
|
- activation payloads
|
|
- host-owned subject details
|
|
|
|
Reload behavior for host-owned projected nodes:
|
|
|
|
```text
|
|
snapshot contains layout for terminal:session-1
|
|
host projects terminal session-1
|
|
-> Workbench restores shell layout
|
|
|
|
snapshot contains layout for terminal:session-1
|
|
host does not project terminal session-1
|
|
-> Workbench does not restore the shell
|
|
```
|
|
|
|
The snapshot may remember presentation for a shell identity, but it is not the
|
|
source of truth for host-owned presence.
|
|
|
|
Snapshot sanitation should preserve only the shell fields Workbench owns and the
|
|
minimal identity metadata required to reconnect shell layout with a host-owned
|
|
business instance. Host-owned business payloads should be stripped or rejected
|
|
before persistence.
|
|
|
|
## External State
|
|
|
|
Node renderers should read host-owned business state through an external state
|
|
source or equivalent host adapter.
|
|
|
|
The lookup input should include stable shell identity:
|
|
|
|
- workspace id
|
|
- node id
|
|
- type id
|
|
- instance id
|
|
- instance key when available
|
|
|
|
If projected node `subject` is needed for lookup, it may be included in live
|
|
render context or external state lookup input. That does not imply that
|
|
`subject` belongs in the persisted snapshot.
|
|
|
|
## Close Semantics
|
|
|
|
Workbench close removes or requests removal of a shell. It must not implicitly
|
|
decide host business lifecycle.
|
|
|
|
For host-owned projected nodes, close usually needs a host callback such as
|
|
`onNodeCloseRequest`. The host decides whether close means:
|
|
|
|
- hide the shell while keeping the business instance alive
|
|
- terminate the business instance
|
|
- mark the instance closed and stop projecting it
|
|
- reject or ignore the close
|
|
|
|
If the host continues projecting the same node after a shell close, Workbench
|
|
will reconcile it back into view. Host-owned close policy must therefore be
|
|
explicit.
|
|
|
|
## Placement In The Package
|
|
|
|
Projected presence reconciliation belongs in `packages/workbench/surface` at the
|
|
Workbench host/session layer.
|
|
|
|
It should not be pushed into:
|
|
|
|
- `packages/workbench/snapshot`, which owns durable snapshot compatibility
|
|
- `packages/workbench/service`, which owns Go snapshot validation and storage
|
|
- the core reducer, which should stay focused on shell state transitions
|
|
- product-specific desktop feature code, where reconciliation would become
|
|
duplicated host glue
|
|
|
|
The lower-level reducer should remain deep and small: given a shell state and a
|
|
window-mechanics action, return the next shell state.
|
|
|
|
The host/session layer is the right module for combining:
|
|
|
|
- node definitions
|
|
- current projected presence
|
|
- loaded snapshot
|
|
- launch results
|
|
- Workbench controller commands
|
|
|
|
## Current Package Contract
|
|
|
|
`@tutti-os/workbench-surface` exposes the Workbench host lifecycle through
|
|
these public mechanisms:
|
|
|
|
- `projectedNodes` for host-owned presence
|
|
- `onLaunchRequest` and `launchNode(...)` for async dock, shortcut, command, or
|
|
host opens
|
|
- `onNodeCloseRequest` and `requestNodeClose(...)` for explicit host close
|
|
policy
|
|
- `activateNode(...)` and render-context `activation` for transient one-shot
|
|
actions
|
|
- `externalStateSource` for host-owned business view state
|
|
- `createWorkbenchHostProjectedNodeId(...)` and
|
|
`createWorkbenchHostLaunchedNodeId(...)` for stable shell id derivation
|
|
|
|
Snapshot sanitization is package-internal. Hosts should provide a repository;
|
|
Workbench owns stripping business payloads before persistence.
|
|
|
|
The public node definition contract describes shell and rendering behavior:
|
|
|
|
- type id
|
|
- default frame
|
|
- dock presentation
|
|
- chrome behavior
|
|
- render body and header
|
|
- shell capabilities
|
|
- single or multi shell mode
|
|
|
|
It does not describe business instance creation, reuse, close policy, or
|
|
business state persistence. Those stay in the host adapter or host services.
|
|
|
|
## Extension Guardrails
|
|
|
|
Allowed helper direction:
|
|
|
|
- stable shell identity helpers
|
|
- snapshot sanitation helpers
|
|
- small type guards for projected node inputs
|
|
|
|
Avoid helpers that make hosts manually restore frame or stack state from
|
|
snapshots. Layout restoration should remain behind WorkbenchHost reconciliation.
|
|
|
|
Avoid definition fields that encode business creation or reuse policy. When a
|
|
host needs custom creation behavior, use `onLaunchRequest`.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- projected node first appearance creates a visible shell
|
|
- projected node with matching snapshot identity restores frame, display mode,
|
|
minimized state, and stack order
|
|
- projected node disappearance removes the shell by default
|
|
- ordinary dock and launch-created nodes continue to work
|
|
- user layout changes are persisted as shell presentation state
|
|
- snapshot does not persist business payloads or activation payloads
|
|
- node renderers can read host-owned data through external state lookup
|
|
- close behavior for host-owned projected nodes is explicit and testable
|