mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
716 lines
21 KiB
Markdown
716 lines
21 KiB
Markdown
# Project-First Host Model
|
|
|
|
## Context
|
|
|
|
We have been exploring how Orca should make VMs, remote servers, SSH machines,
|
|
and future cloud-hosted compute feel first class.
|
|
|
|
The current implementation direction groups the workspace sidebar by execution
|
|
host:
|
|
|
|
```text
|
|
Local Mac
|
|
Project A
|
|
workspace-1
|
|
SSH / VM 1
|
|
Project A
|
|
workspace-2
|
|
```
|
|
|
|
That model is useful as an operational view, but it makes the machine feel like
|
|
the outermost user concept. After discussion, the stronger long-term product
|
|
model is project-first:
|
|
|
|
```text
|
|
Project A
|
|
Local Mac
|
|
workspace-1
|
|
Cloud VM 1
|
|
workspace-2
|
|
```
|
|
|
|
In this model, machines are not separate isolated workspaces. They are places
|
|
where a project can be available and where a workspace can run.
|
|
|
|
## Reference Findings
|
|
|
|
### Superset
|
|
|
|
Superset is closest to the desired Orca model.
|
|
|
|
Its conceptual model is:
|
|
|
|
```text
|
|
Project + Host -> Workspace
|
|
```
|
|
|
|
Specific details:
|
|
|
|
- A project is the durable repo concept.
|
|
- A host is a registered machine that can run workspaces.
|
|
- A workspace stores both `projectId` and `hostId`.
|
|
- Workspace creation is explicitly host-targeted: pick a project, pick a host,
|
|
then create the workspace on that host.
|
|
- The schema has a uniqueness rule for a "main" workspace per
|
|
`(projectId, hostId)`, which means the same project can be materialized on
|
|
multiple hosts.
|
|
- Project setup is host-scoped. A project can be cloned or imported on a
|
|
specific host.
|
|
- The UI can block workspace creation with "Project not set up on this host."
|
|
- Project settings have host-aware pieces like project location and worktree
|
|
location on the selected host.
|
|
|
|
This maps well to Orca because Orca already thinks in repos/projects,
|
|
worktrees, tasks, agents, and terminals.
|
|
|
|
### Cmux
|
|
|
|
Cmux is more workspace/session-first.
|
|
|
|
Its conceptual model is closer to:
|
|
|
|
```text
|
|
Workspace/session -> local or remote execution context
|
|
```
|
|
|
|
Specific details:
|
|
|
|
- `cmux ssh user@remote` creates a workspace for a remote machine.
|
|
- Remote/SSH is a property of the workspace/session.
|
|
- Browser panes can route through the remote network, so remote `localhost`
|
|
works naturally.
|
|
- File explorer follows SSH workspaces and shows the remote root.
|
|
- Remote sessions have remote configuration and reconnect/persistence behavior.
|
|
- Cmux has project-specific command config, but it does not appear to center a
|
|
durable "Project is available on hosts X/Y/Z" abstraction.
|
|
|
|
Cmux is a strong reference for SSH/session polish, but not the best reference
|
|
for Orca's project/worktree data model.
|
|
|
|
## Recommended Orca Model
|
|
|
|
The recommended durable model is:
|
|
|
|
```text
|
|
Project -> ProjectHostSetup -> Workspace
|
|
```
|
|
|
|
Where:
|
|
|
|
- `Project` is the durable repo identity.
|
|
- `ProjectHostSetup` means "this project is available on this host at this
|
|
path, with this setup state and host-specific config."
|
|
- `Workspace` is a branch/task/worktree instance of a project on one host.
|
|
|
|
Potential names for `ProjectHostSetup`:
|
|
|
|
- `ProjectInstallation`
|
|
- `ProjectHostSetup`
|
|
- `ProjectLocation`
|
|
- `HostProject`
|
|
|
|
`ProjectHostSetup` is probably the clearest product/data term for now.
|
|
|
|
## Current Orca Model Inventory
|
|
|
|
Orca currently has pieces of the new model, but they are attached to the wrong
|
|
concepts for a project-first product.
|
|
|
|
### Repo Is Both Project And Host Setup
|
|
|
|
`Repo` currently represents the user's project in the UI, but it also owns
|
|
host-local setup fields:
|
|
|
|
- `path`
|
|
- `worktreeBasePath`
|
|
- `connectionId`
|
|
- `executionHostId`
|
|
- `hookSettings`
|
|
- `gitUsername`
|
|
- repo-specific source-control overrides
|
|
|
|
That means two checkouts of the same project on two machines become two repos,
|
|
even when the user thinks of them as one project.
|
|
|
|
In the project-first model:
|
|
|
|
- project identity should move to `Project`
|
|
- host-local checkout information should move to `ProjectHostSetup`
|
|
- compatibility can keep `Repo` as a transitional projection for old APIs
|
|
|
|
### Worktree Belongs To Repo Only
|
|
|
|
`Worktree` currently stores `repoId`, and the host is inferred from the owning
|
|
repo. This works when "repo" means "checkout on one host", but it is awkward
|
|
when one project can exist on several hosts.
|
|
|
|
In the project-first model, a workspace should know:
|
|
|
|
- `projectId`
|
|
- `hostId`
|
|
- the selected `projectHostSetupId`
|
|
- the worktree path on that host
|
|
|
|
The existing `repoId` can initially point at a compatibility setup id, but the
|
|
durable direction should be explicit.
|
|
|
|
### Persistence Stores Repos As The Durable Root
|
|
|
|
`PersistedState` currently stores `repos: Repo[]`, `projectGroups`, and
|
|
worktree metadata keyed around repo/worktree ids. Recent multi-host work also
|
|
stores per-host session partitions, which is good for runtime ownership, but it
|
|
does not create a durable "project is set up on host" record.
|
|
|
|
The migration should derive:
|
|
|
|
- one `Project` per existing user-visible project identity
|
|
- one `ProjectHostSetup` per existing `Repo`
|
|
- one `Host` from local, SSH, runtime, and future cloud targets
|
|
- existing worktrees attached to the setup derived from their current repo
|
|
|
|
For a local-only user this should be boring: every existing repo becomes a
|
|
project with one local setup.
|
|
|
|
### Renderer Store Is Repo-Centric
|
|
|
|
The renderer store has repo-first actions:
|
|
|
|
- `fetchRepos`
|
|
- `addRepoPath`
|
|
- `addRepo`
|
|
- `removeProject`
|
|
- `updateRepo`
|
|
- `fetchWorktrees(repoId)`
|
|
- `createWorktree(repoId, ...)`
|
|
|
|
Remote runtime support already chooses a target based on the active runtime or
|
|
repo owner, but the public shape is still repo-centric. A project-first API
|
|
needs calls like:
|
|
|
|
- `fetchProjects`
|
|
- `fetchProjectHostSetups(projectId)`
|
|
- `setupProjectOnHost(projectId, hostId, ...)`
|
|
- `createWorkspace({ projectId, hostId, ... })`
|
|
|
|
During migration, these can be implemented as wrappers around the current repo
|
|
APIs so the change is incremental.
|
|
|
|
### Add Project Means Add A Host-Local Checkout
|
|
|
|
Local `repos:add` and SSH `repos:addRemote` both persist a repo at a concrete
|
|
path. That path is the important host-local fact, but the UI labels the result
|
|
as a project.
|
|
|
|
In the new model, the add/setup flows split into three actions:
|
|
|
|
- create or import a durable project identity
|
|
- set up that project on a specific host
|
|
- create workspaces from any ready setup
|
|
|
|
### Runtime Ownership Is Already Pointing The Right Way
|
|
|
|
Terminals, sessions, remote PTYs, browser routing, and runtime RPC already have
|
|
host-aware pieces. The problem is that host ownership is inferred through repo
|
|
ownership rather than declared on the workspace/setup model.
|
|
|
|
The new model should preserve the current runtime routing discipline while
|
|
making host ownership explicit in the data model.
|
|
|
|
## Data Model Shape
|
|
|
|
### Project
|
|
|
|
Project-global state:
|
|
|
|
- id
|
|
- display name
|
|
- repo identity / provider metadata
|
|
- icon/color
|
|
- default branch
|
|
- Git provider linkage
|
|
- project-global settings
|
|
|
|
### Host
|
|
|
|
Host-global state:
|
|
|
|
- id
|
|
- kind: local, SSH, runtime, cloud VM
|
|
- label
|
|
- online/health/compatibility status
|
|
- platform/capabilities
|
|
- host-wide settings
|
|
- agent availability
|
|
|
|
### ProjectHostSetup
|
|
|
|
Host-specific project state:
|
|
|
|
- project id
|
|
- host id
|
|
- repo path on that host
|
|
- worktree base directory on that host
|
|
- setup state: not set up, setting up, ready, error, unsupported
|
|
- setup method: imported existing folder, cloned repo, provisioned by cloud
|
|
- platform/capability constraints
|
|
- host-specific project settings
|
|
- optional setup/teardown scripts
|
|
|
|
### Workspace
|
|
|
|
Workspace state:
|
|
|
|
- project id
|
|
- host id
|
|
- project host setup id, if we make that a real id
|
|
- branch/worktree name
|
|
- worktree path on the host
|
|
- task/PR/issue linkage
|
|
- agent/terminal/browser resources owned by that host
|
|
|
|
## UX Model
|
|
|
|
### Sidebar
|
|
|
|
Default sidebar should become project-first:
|
|
|
|
```text
|
|
Project A
|
|
feature-login Local Mac
|
|
benchmark-fix GPU VM
|
|
|
|
Project B
|
|
auth-refactor Work Linux
|
|
```
|
|
|
|
When a project has workspaces on multiple hosts, we can optionally show host
|
|
subgroups:
|
|
|
|
```text
|
|
Project A
|
|
Local Mac
|
|
feature-login
|
|
GPU VM
|
|
benchmark-fix
|
|
```
|
|
|
|
Rules:
|
|
|
|
- If a project only has one host represented, do not add noisy host nesting.
|
|
- If a project has multiple hosts, host subgroups can appear automatically.
|
|
- Host should remain available as a filter/view mode.
|
|
- The current host-first grouping can survive as an alternate operational view,
|
|
but should not be the default mental model.
|
|
|
|
### Create Workspace
|
|
|
|
Workspace creation should ask:
|
|
|
|
1. Which project?
|
|
2. What branch/task/name?
|
|
3. Which host should run it?
|
|
4. If the project is not set up on that host, set it up inline or block with a
|
|
clear action.
|
|
|
|
Example:
|
|
|
|
```text
|
|
Create workspace
|
|
|
|
Project: Orca
|
|
Branch: feature/remote-hosts
|
|
Run on: GPU VM 1
|
|
|
|
This project is not set up on GPU VM 1.
|
|
[Clone repo to host] [Import existing folder] [Cancel]
|
|
```
|
|
|
|
### Set Up Project On A Host
|
|
|
|
A project settings page should expose which hosts the project is available on:
|
|
|
|
```text
|
|
Project: Orca
|
|
|
|
Available on:
|
|
Local Mac Ready /Users/me/orca
|
|
GPU VM 1 Ready /home/me/orca
|
|
Work Linux Not set up [Set up]
|
|
```
|
|
|
|
Setup methods:
|
|
|
|
- clone from repo URL into a selected parent directory
|
|
- import an existing folder on the host
|
|
- future: provision cloud VM and clone automatically
|
|
|
|
### Add New Host / VM
|
|
|
|
Adding a host should not automatically attach every project to it.
|
|
|
|
After adding a host, Orca should offer:
|
|
|
|
```text
|
|
New host connected: GPU VM 1
|
|
|
|
Make projects available here:
|
|
[ ] Orca Clone to /home/me/orca
|
|
[ ] Backend Import existing folder
|
|
[ ] ML Runner Clone to /mnt/work/ml-runner
|
|
```
|
|
|
|
This is also the natural place for future cloud VM monetization:
|
|
|
|
1. provision host
|
|
2. choose projects to materialize there
|
|
3. create workspaces on that host
|
|
|
|
## Edge Cases
|
|
|
|
### Project Exists Only On One Host
|
|
|
|
This is normal. The project has one `ProjectHostSetup`.
|
|
|
|
The UI should not imply every project can run everywhere.
|
|
|
|
### Project Requires Linux Or Beefy Hardware
|
|
|
|
This is also normal. The project can mark local Mac as unsupported or simply not
|
|
set up. Create-workspace host choices should only show valid hosts by default,
|
|
with an affordance to reveal unavailable hosts and why they are unavailable.
|
|
|
|
### Work Projects Versus Personal Projects
|
|
|
|
Do not solve this with host grouping alone. This is better represented by:
|
|
|
|
- project ownership/account
|
|
- project tags/groups
|
|
- host availability
|
|
- workspace filters
|
|
|
|
### Existing Project On Computer A, Add To Computer B
|
|
|
|
Use "Set up project on host":
|
|
|
|
- clone from remote into a host path, or
|
|
- import an existing folder on the host.
|
|
|
|
### Add VM And Initialize Many Projects
|
|
|
|
Use a bulk "Make projects available on this host" flow. Each selected project
|
|
still needs a per-host location/method.
|
|
|
|
## What Needs To Change
|
|
|
|
This is a large model change. It is not just a sidebar reorder.
|
|
|
|
At a high level, 12 areas need to change.
|
|
|
|
### 1. Data Model
|
|
|
|
Add a first-class project-host setup record.
|
|
|
|
Current host ownership is mostly attached to repos/workspaces through
|
|
execution-host IDs. The new model needs a durable record for "project X is
|
|
available on host Y at path Z."
|
|
|
|
Concrete changes:
|
|
|
|
- add `Project`
|
|
- add `ProjectHostSetup`
|
|
- decide whether existing `Repo` becomes a compatibility projection, a renamed
|
|
setup type, or is gradually replaced
|
|
- add selectors that answer "which setups exist for this project?" and "which
|
|
host owns this workspace?"
|
|
|
|
### 2. Persistence And Migration
|
|
|
|
Existing repos/worktrees need to migrate into:
|
|
|
|
- project records
|
|
- host records
|
|
- project-host setup records
|
|
- workspace records tied to both project and host
|
|
|
|
For current local-only users, migration should feel invisible: each project gets
|
|
a local-host setup.
|
|
|
|
Concrete changes:
|
|
|
|
- bump schema version
|
|
- migrate every existing `Repo` into a `Project` plus one `ProjectHostSetup`
|
|
- preserve old repo ids or create an alias map so worktree metadata, terminal
|
|
panes, caches, hooks, automations, and settings do not lose references
|
|
- keep downgrade behavior in mind because current persisted state is read by
|
|
older builds
|
|
|
|
### 3. Sidebar Row Model
|
|
|
|
The sidebar should group primarily by project, not host.
|
|
|
|
Host grouping becomes nested under projects only when helpful, or becomes a
|
|
filter/view option.
|
|
|
|
Concrete changes:
|
|
|
|
- build sidebar rows from projects, setups, hosts, and workspaces
|
|
- show host labels inline for mixed-host projects without adding unnecessary
|
|
nesting
|
|
- keep the host-first view/filter as an operational mode if it remains useful
|
|
- revisit drag/reorder so project order, host order within a project, and
|
|
workspace order remain understandable
|
|
|
|
### 4. Workspace Creation
|
|
|
|
Create workspace needs a host picker that is constrained by project setup.
|
|
|
|
If the selected host does not have the project, the flow needs setup actions
|
|
instead of silently failing or creating an ambiguous remote workspace.
|
|
|
|
Concrete changes:
|
|
|
|
- change creation input from `repoId` to `{ projectId, hostId }`
|
|
- list ready setups first and unavailable hosts with clear reasons
|
|
- inline setup/import/clone when a project is not available on the chosen host
|
|
- ensure created workspaces persist explicit host/setup ownership
|
|
|
|
### 5. Project Setup / Add Project
|
|
|
|
Adding a project must distinguish:
|
|
|
|
- create a new project identity
|
|
- set up that project on this host
|
|
- set up an existing project on another host
|
|
|
|
This likely replaces a single "add repo" flow with a project-first setup flow.
|
|
|
|
Concrete changes:
|
|
|
|
- add "Set up on this host" flows for local paths, SSH paths, runtime hosts,
|
|
and future cloud VMs
|
|
- support clone and import-existing-folder
|
|
- support bulk setup when a new host is added
|
|
- keep current add-repo flows as compatibility entry points during migration
|
|
|
|
### 6. Project Settings
|
|
|
|
Project settings need a host selector or host table for host-specific settings:
|
|
|
|
- repo location
|
|
- worktree base dir
|
|
- setup scripts
|
|
- branch prefix
|
|
- platform/capability notes
|
|
|
|
Project-global settings remain global.
|
|
|
|
Concrete changes:
|
|
|
|
- split settings into project-global and host-specific sections
|
|
- use a host dropdown/table for location, worktree base path, setup scripts, and
|
|
platform constraints
|
|
- keep source-control and review settings provider-aware, not GitHub-only
|
|
- make the "which host am I editing?" answer explicit on every host-specific
|
|
settings pane
|
|
|
|
### 7. Host Settings
|
|
|
|
Host settings remain host-global:
|
|
|
|
- connection details
|
|
- server version/compatibility
|
|
- default worktree directory
|
|
- agents available on that host
|
|
- platform/capabilities
|
|
|
|
They should not become a separate copy of all project settings.
|
|
|
|
Concrete changes:
|
|
|
|
- expose host connection, health, version, platform, and capabilities
|
|
- include compatibility warnings for mismatched client/server versions
|
|
- keep host-global defaults separate from per-project setup overrides
|
|
|
|
### 8. Runtime Ownership
|
|
|
|
Terminals, browser panes, agents, PTYs, filesystem operations, and setup scripts
|
|
must route through the workspace's host.
|
|
|
|
The UI can show project-first organization, but execution still happens on the
|
|
owning host.
|
|
|
|
Concrete changes:
|
|
|
|
- derive runtime target from workspace/setup host, not active sidebar grouping
|
|
- keep local, SSH, runtime, and future cloud execution behind the same routing
|
|
contract
|
|
- audit filesystem, git, terminal, browser, agent, hook, and automation paths
|
|
for repo-id assumptions
|
|
|
|
### 9. Compatibility And Availability
|
|
|
|
Workspace creation must handle:
|
|
|
|
- host offline
|
|
- project not set up
|
|
- host version too old
|
|
- client version too old
|
|
- unsupported platform
|
|
- missing agent on selected host
|
|
|
|
This should be surfaced before creation where possible.
|
|
|
|
Concrete changes:
|
|
|
|
- add capability/version probing to host records
|
|
- gate project setup and workspace creation on host readiness
|
|
- define behavior for new client/old server and old client/new server
|
|
- keep unsupported actions disabled with a specific reason
|
|
|
|
### 10. CLI / API
|
|
|
|
CLI and API commands need to accept the project-first model:
|
|
|
|
```bash
|
|
orca project setup --project <id> --host <id> --clone ...
|
|
orca workspace create --project <id> --host <id> --branch ...
|
|
orca project hosts list <project-id>
|
|
```
|
|
|
|
Existing commands should keep compatibility aliases where possible.
|
|
|
|
Concrete changes:
|
|
|
|
- add project/setup/workspace commands that take host explicitly
|
|
- keep old repo/worktree commands working as aliases where possible
|
|
- return structured availability errors instead of generic failures
|
|
|
|
### 11. Caches, Metadata, And Request Ownership
|
|
|
|
Caches and request ownership need to follow the same identity split.
|
|
|
|
Project-global caches can stay project keyed. Host-local caches must include the
|
|
host/setup key because two machines can have different refs, branches, worktree
|
|
paths, installed agents, filesystem state, and server capabilities for the same
|
|
project.
|
|
|
|
Concrete changes:
|
|
|
|
- decide which caches are project-global versus host/setup-local
|
|
- include host/setup ids in branch, worktree, status, filesystem, terminal, and
|
|
remote capability cache keys
|
|
- keep request cancellation scoped to the host that owns the operation
|
|
|
|
### 12. Tests And Validation
|
|
|
|
The validation surface is broad because this changes identity, persistence,
|
|
runtime routing, and UI organization.
|
|
|
|
Concrete changes:
|
|
|
|
- migration tests for local, SSH, runtime, duplicate project-on-two-hosts, and
|
|
missing/offline hosts
|
|
- selector tests for project/setup/workspace grouping
|
|
- workspace creation tests for ready, not set up, offline, incompatible, and
|
|
unsupported hosts
|
|
- sidebar tests for single-host projects, mixed-host projects, host filters, and
|
|
drag/reorder
|
|
- SSH end-to-end validation for remote setup and remote workspace creation
|
|
- Electron UI verification for the create-workspace and settings flows
|
|
|
|
## Implementation Scale
|
|
|
|
This is probably not a small patch.
|
|
|
|
Estimated change categories: 12 meaningful surfaces.
|
|
|
|
1. shared types and persistence
|
|
2. migration logic
|
|
3. main-process project/host setup APIs
|
|
4. renderer store normalization/selectors
|
|
5. sidebar grouping and drag/reorder behavior
|
|
6. create workspace flow
|
|
7. add/setup project flow
|
|
8. project settings
|
|
9. host settings
|
|
10. runtime routing/guards
|
|
11. CLI/API updates
|
|
12. tests and compatibility coverage
|
|
|
|
So the answer is: about 12 meaningful product/engineering surfaces need to
|
|
change, with the data model, migration, creation/setup flows, and runtime
|
|
routing being the most important and highest-risk pieces.
|
|
|
|
## Suggested Implementation Sequence
|
|
|
|
This should be implemented as an additive migration, not a big-bang rename.
|
|
|
|
1. Add project/setup types, selectors, and compatibility helpers while keeping
|
|
existing `Repo` APIs alive.
|
|
2. Add persistence migration that derives one setup per existing repo.
|
|
3. Update store selectors so the sidebar and creation flows can read
|
|
project-first data without requiring every backend call to change at once.
|
|
4. Update workspace creation to accept project plus host, then map through the
|
|
selected setup to current worktree creation internals.
|
|
5. Add setup-on-host flows for local and SSH paths.
|
|
6. Split settings into project-global and host-specific sections with an
|
|
explicit host selector.
|
|
7. Move sidebar default grouping to project-first while preserving host filters
|
|
and host-first operational mode if we still want it.
|
|
8. Audit runtime routing and caches so every host-local operation is keyed by
|
|
setup/host, not only project.
|
|
9. Add CLI/API compatibility commands.
|
|
10. Run migration, unit, SSH, and Electron validation before calling it done.
|
|
|
|
## Implementation Status
|
|
|
|
Landed so far:
|
|
|
|
- Added shared `Project` and `ProjectHostSetup` types.
|
|
- Added a pure compatibility projection from existing `Repo[]` into
|
|
project-first `Project[]` and `ProjectHostSetup[]`.
|
|
- Added renderer store selectors that expose the projected model without
|
|
duplicating derived state in Zustand.
|
|
- Added persisted `projects` and `projectHostSetups` compatibility fields that
|
|
are backfilled from existing repos on load and kept in sync when repos are
|
|
added, updated, reordered, or removed.
|
|
- Exposed read-only project/setup list APIs through local IPC, preload, and
|
|
runtime RPC so newer clients can ask local or remote servers for the
|
|
project-first compatibility model.
|
|
- Hydrated renderer store `projects` and `projectHostSetups` alongside repos,
|
|
with a repo-derived fallback for older preloads/runtimes that do not yet
|
|
implement the project APIs.
|
|
- Updated the sidebar `groupBy: repo` row builder to group by durable project
|
|
identity when project/setup data exists, while keeping a repo-by-repo fallback
|
|
for projects that have not been linked across hosts.
|
|
- Added tests for local repos, SSH repos, same-provider multi-host grouping,
|
|
no-identity same-name non-grouping, selector cache behavior, persistence
|
|
backfill, repo mutation synchronization, renderer hydration, and runtime RPC
|
|
routing. Sidebar row-builder tests now cover project-first multi-host grouping
|
|
and same-name repo separation without project identity.
|
|
|
|
Important limitation:
|
|
|
|
- This is not the full migration yet. `Repo` remains the source of truth for the
|
|
compatibility records, and create-workspace/settings/sidebar flows still use
|
|
the current repo-centric APIs until the later steps above are implemented.
|
|
|
|
## Recommendation
|
|
|
|
Use the current host-first sidebar work as a useful transitional and optional
|
|
operational view.
|
|
|
|
For the long-term Orca model, move to project-first:
|
|
|
|
```text
|
|
Project -> ProjectHostSetup -> Workspace
|
|
```
|
|
|
|
This gives us:
|
|
|
|
- a less jarring experience for local-only users
|
|
- clean support for SSH machines and VMs
|
|
- clear handling for project exclusivity
|
|
- a natural future cloud VM monetization path
|
|
- a better fit for repo/worktree/task/agent workflows
|