mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 08:03:22 +00:00
1384 lines
47 KiB
HTML
1384 lines
47 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Orca Host Model: Tasks, Automations, Provider Identity</title>
|
||
<style>
|
||
:root {
|
||
color-scheme: dark;
|
||
--background: #111111;
|
||
--foreground: #f4f4f5;
|
||
--card: #161618;
|
||
--popover: #18181b;
|
||
--muted: #1d1d20;
|
||
--muted-foreground: #a1a1aa;
|
||
--border: #2a2a2f;
|
||
--accent: #242429;
|
||
--accent-foreground: #fafafa;
|
||
--input: #18181b;
|
||
--ring: #d4d4d8;
|
||
--sidebar: #141416;
|
||
--sidebar-accent: #232327;
|
||
--sidebar-border: #2b2b30;
|
||
--success: #7dd3a7;
|
||
--warning: #f4c56a;
|
||
--danger: #f08c8c;
|
||
--info: #9dbcfb;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
html {
|
||
background: var(--background);
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--background);
|
||
color: var(--foreground);
|
||
font-family:
|
||
Geist,
|
||
ui-sans-serif,
|
||
system-ui,
|
||
-apple-system,
|
||
BlinkMacSystemFont,
|
||
"Segoe UI",
|
||
sans-serif;
|
||
letter-spacing: 0.01em;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
main {
|
||
max-width: 1240px;
|
||
margin: 0 auto;
|
||
padding: 42px 24px 72px;
|
||
}
|
||
|
||
header {
|
||
border-bottom: 1px solid var(--border);
|
||
padding-bottom: 28px;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
h1,
|
||
h2,
|
||
h3,
|
||
h4 {
|
||
letter-spacing: 0;
|
||
line-height: 1.15;
|
||
}
|
||
|
||
h1 {
|
||
margin: 8px 0 12px;
|
||
font-size: 34px;
|
||
}
|
||
|
||
h2 {
|
||
margin: 34px 0 14px;
|
||
font-size: 22px;
|
||
}
|
||
|
||
h3 {
|
||
margin: 22px 0 10px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
h4 {
|
||
margin: 0 0 8px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
p {
|
||
margin: 0 0 12px;
|
||
}
|
||
|
||
ul {
|
||
margin: 8px 0 0;
|
||
padding-left: 18px;
|
||
}
|
||
|
||
li {
|
||
margin: 6px 0;
|
||
}
|
||
|
||
code {
|
||
border: 1px solid var(--border);
|
||
border-radius: 6px;
|
||
background: var(--muted);
|
||
color: var(--foreground);
|
||
font-family:
|
||
SFMono-Regular,
|
||
Consolas,
|
||
"Liberation Mono",
|
||
monospace;
|
||
font-size: 0.92em;
|
||
padding: 1px 5px;
|
||
}
|
||
|
||
button,
|
||
input,
|
||
select {
|
||
font: inherit;
|
||
}
|
||
|
||
.eyebrow {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
font-weight: 650;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.lede {
|
||
max-width: 900px;
|
||
color: var(--muted-foreground);
|
||
font-size: 14px;
|
||
}
|
||
|
||
.grid {
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.grid-2 {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.grid-3 {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
}
|
||
|
||
.panel {
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
background: var(--card);
|
||
padding: 16px;
|
||
}
|
||
|
||
.panel.compact {
|
||
padding: 12px;
|
||
}
|
||
|
||
.callout {
|
||
border: 1px solid color-mix(in srgb, var(--info) 28%, var(--border));
|
||
border-radius: 8px;
|
||
background: color-mix(in srgb, var(--info) 8%, var(--card));
|
||
padding: 14px 16px;
|
||
}
|
||
|
||
.muted {
|
||
color: var(--muted-foreground);
|
||
}
|
||
|
||
.tiny {
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.status {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 999px;
|
||
background: var(--muted-foreground);
|
||
}
|
||
|
||
.dot.online {
|
||
background: var(--success);
|
||
}
|
||
|
||
.dot.warning {
|
||
background: var(--warning);
|
||
}
|
||
|
||
.dot.offline {
|
||
background: #73737c;
|
||
}
|
||
|
||
.tag-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
min-height: 24px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 999px;
|
||
background: var(--muted);
|
||
color: var(--muted-foreground);
|
||
padding: 2px 9px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.tag.strong {
|
||
color: var(--foreground);
|
||
background: var(--accent);
|
||
}
|
||
|
||
.checklist {
|
||
display: grid;
|
||
gap: 8px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.check-row {
|
||
display: grid;
|
||
grid-template-columns: 22px minmax(0, 1fr) auto;
|
||
gap: 10px;
|
||
align-items: start;
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
background: color-mix(in srgb, var(--card) 86%, var(--muted));
|
||
padding: 10px 12px;
|
||
}
|
||
|
||
.box {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-top: 2px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
color: var(--success);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.priority {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
}
|
||
|
||
.mock-shell {
|
||
overflow: hidden;
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
background: var(--background);
|
||
}
|
||
|
||
.mock-titlebar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 38px;
|
||
border-bottom: 1px solid var(--border);
|
||
background: #151518;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.window-dots {
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
|
||
.window-dots span {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 999px;
|
||
background: #3a3a40;
|
||
}
|
||
|
||
.mock-app {
|
||
display: grid;
|
||
grid-template-columns: 238px minmax(0, 1fr);
|
||
min-height: 520px;
|
||
}
|
||
|
||
.sidebar {
|
||
border-right: 1px solid var(--sidebar-border);
|
||
background: var(--sidebar);
|
||
padding: 12px;
|
||
}
|
||
|
||
.sidebar-header,
|
||
.side-section-title {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
font-weight: 650;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.side-section-title {
|
||
margin: 16px 6px 7px;
|
||
}
|
||
|
||
.side-row {
|
||
display: grid;
|
||
grid-template-columns: 18px minmax(0, 1fr) auto;
|
||
gap: 8px;
|
||
align-items: center;
|
||
min-height: 32px;
|
||
border-radius: 6px;
|
||
padding: 6px 8px;
|
||
color: var(--muted-foreground);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.side-row.current,
|
||
.side-row:hover {
|
||
background: var(--sidebar-accent);
|
||
color: var(--foreground);
|
||
}
|
||
|
||
.side-count {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.content {
|
||
min-width: 0;
|
||
background: var(--background);
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 12px 16px;
|
||
}
|
||
|
||
.toolbar-main {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.tabs {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
border: 1px solid var(--border);
|
||
border-radius: 7px;
|
||
background: var(--muted);
|
||
padding: 2px;
|
||
}
|
||
|
||
.tab {
|
||
min-height: 26px;
|
||
border: 0;
|
||
border-radius: 5px;
|
||
background: transparent;
|
||
color: var(--muted-foreground);
|
||
padding: 0 10px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.tab.active {
|
||
background: var(--accent);
|
||
color: var(--foreground);
|
||
}
|
||
|
||
.select-like,
|
||
.button-like {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
min-height: 32px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 7px;
|
||
background: var(--input);
|
||
color: var(--foreground);
|
||
padding: 0 10px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.button-like {
|
||
background: var(--accent);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.list {
|
||
padding: 10px 14px 14px;
|
||
}
|
||
|
||
.task-row,
|
||
.automation-row,
|
||
.settings-row {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
gap: 12px;
|
||
align-items: center;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
|
||
padding: 12px 2px;
|
||
}
|
||
|
||
.task-title,
|
||
.automation-title {
|
||
overflow: hidden;
|
||
color: var(--foreground);
|
||
font-size: 13px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.meta-line {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-top: 4px;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.identity-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 999px;
|
||
background: var(--muted);
|
||
color: var(--muted-foreground);
|
||
padding: 2px 8px;
|
||
font-size: 11px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.split {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.1fr) minmax(280px, 0.9fr);
|
||
gap: 12px;
|
||
padding: 14px;
|
||
}
|
||
|
||
.form {
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.field {
|
||
display: grid;
|
||
gap: 6px;
|
||
}
|
||
|
||
.label {
|
||
color: var(--muted-foreground);
|
||
font-size: 11px;
|
||
font-weight: 650;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.input-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.input-row .select-like {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.notice {
|
||
border: 1px solid color-mix(in srgb, var(--warning) 30%, var(--border));
|
||
border-radius: 8px;
|
||
background: color-mix(in srgb, var(--warning) 7%, var(--card));
|
||
color: var(--muted-foreground);
|
||
padding: 10px 12px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.mock-caption {
|
||
margin: 10px 0 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.table {
|
||
overflow: hidden;
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.table-row {
|
||
display: grid;
|
||
grid-template-columns: 170px minmax(0, 1fr) 180px;
|
||
gap: 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 10px 12px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.table-row:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.table-head {
|
||
background: var(--muted);
|
||
color: var(--muted-foreground);
|
||
font-weight: 650;
|
||
}
|
||
|
||
.hidden {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
main {
|
||
padding-inline: 16px;
|
||
}
|
||
|
||
.grid-2,
|
||
.grid-3,
|
||
.split {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.mock-app {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.sidebar {
|
||
display: none;
|
||
}
|
||
|
||
.toolbar {
|
||
align-items: stretch;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.toolbar-main {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.table-row {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main>
|
||
<header>
|
||
<div class="eyebrow">Planning artifact · Host model follow-up</div>
|
||
<h1>Tasks, Automations, and Provider Identity Under One Host Model</h1>
|
||
<p class="lede">
|
||
The project-first migration gives Orca the durable shape
|
||
<code>Project -> ProjectHostSetup -> Workspace</code>. The remaining product gap is
|
||
that Tasks, Automations, and provider integrations still route through different
|
||
ownership rules. This plan makes <strong>Host</strong> the user-facing concept across
|
||
Local Mac, SSH machines, Remote Servers, and future Orca cloud VMs.
|
||
</p>
|
||
<div class="tag-row">
|
||
<span class="tag strong">Host = Local / SSH / Remote Server / Cloud VM</span>
|
||
<span class="tag">Project identity stays above hosts</span>
|
||
<span class="tag">Provider accounts become host-scoped where needed</span>
|
||
<span class="tag">Automations get explicit run location</span>
|
||
</div>
|
||
</header>
|
||
|
||
<section>
|
||
<h2>Short Answer</h2>
|
||
<div class="callout">
|
||
<p>
|
||
We should keep the model simple for users: a project can be available on one or more
|
||
hosts, and every host can have its own filesystem, terminals, provider CLIs, auth, and
|
||
runtime capabilities. Tasks and Automations should stop relying on ambient global state
|
||
where the host matters.
|
||
</p>
|
||
<p>
|
||
The big change is not “make SSH and Remote Server the same internally.” It is “present
|
||
both as hosts, then route each workflow through the selected host’s capabilities.”
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Host Boundaries</h2>
|
||
<div class="table">
|
||
<div class="table-row table-head">
|
||
<div>Host kind</div>
|
||
<div>What explicit task context means</div>
|
||
<div>Boundary</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Local Mac</div>
|
||
<div>
|
||
Provider calls, repo discovery, task launch, and workspace creation use the local
|
||
desktop environment.
|
||
</div>
|
||
<div>Baseline path.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>SSH host</div>
|
||
<div>
|
||
The Tasks page should know the selected project setup lives on an SSH machine and show
|
||
whether provider data is served by the SSH host or temporarily by the desktop client.
|
||
</div>
|
||
<div>
|
||
SSH is first-class host context, but support is capability-based: filesystem,
|
||
terminal, git, and provider CLI/token execution may arrive independently.
|
||
</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Remote Server / runtime</div>
|
||
<div>
|
||
Provider calls should route through the remote Orca runtime when that runtime owns
|
||
the selected project setup and advertises the needed capability.
|
||
</div>
|
||
<div>
|
||
Richer host with runtime RPC, version/capability negotiation, web/mobile handoff, and
|
||
more durable background services.
|
||
</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Future Cloud VM</div>
|
||
<div>
|
||
Same user-facing host model: a project setup on that VM can serve Tasks and create
|
||
Automations once the VM exposes the required host capabilities.
|
||
</div>
|
||
<div>Provisioning lifecycle remains separate from task/provider routing.</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Task Source vs Run Host</h2>
|
||
<div class="callout">
|
||
<p>
|
||
A logical project can exist on multiple hosts, but provider data still has to be fetched
|
||
through one credential context. That source context must be explicit or at least visible.
|
||
“Project: orca” is not enough information when Local Mac has GitHub account A and
|
||
openclaw 2 has GitHub account B.
|
||
</p>
|
||
</div>
|
||
<div class="grid grid-2">
|
||
<div class="panel">
|
||
<div class="eyebrow">Task source context</div>
|
||
<h3>Where issues/PRs are fetched from</h3>
|
||
<p class="tiny">
|
||
This answers: which host's GitHub/GitLab/Linear/Jira credentials serve the list? It
|
||
affects private repo access, rate limits, viewer-specific filters like “assigned to
|
||
me,” review requests, notifications, and mutation permissions.
|
||
</p>
|
||
</div>
|
||
<div class="panel">
|
||
<div class="eyebrow">Run host</div>
|
||
<h3>Where the workspace is created</h3>
|
||
<p class="tiny">
|
||
This answers: when the user starts work from a task, which project-host setup creates
|
||
the workspace? It may default to the task source host, but the user can choose another
|
||
ready setup when the project exists there.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="notice" style="margin-top: 12px">
|
||
Recommendation: default the task source to the active workspace host or the last-used host
|
||
for that project/provider, show the serving account beside the picker, and require an
|
||
explicit choice when combining hosts would make “me” ambiguous.
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>What Needs To Change</h2>
|
||
<div class="checklist">
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Unify provider request ownership around Host.</strong>
|
||
<div class="tiny">
|
||
GitHub currently has per-repo runtime routing, while SSH/local are desktop-owned.
|
||
Linear/Jira use active runtime. GitLab uses desktop IPC with SSH-aware repo paths.
|
||
We need a shared provider request target: <code>{ provider, hostId, projectHostSetupId? }</code>.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Make Tasks choose an explicit host context.</strong>
|
||
<div class="tiny">
|
||
Applies to Local, SSH, Remote Server, and future Cloud VM hosts. The Tasks page
|
||
should show which host/account is serving results. Multi-project and multi-host
|
||
selections should either group by host or require a selected host when provider
|
||
identity can differ.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Store Automations as project + run-host, not repo-id pretending to be project-id.</strong>
|
||
<div class="tiny">
|
||
Existing automations store <code>projectId</code> as a repo id. New automations
|
||
should target a logical project and either an existing workspace or a
|
||
<code>projectHostSetupId</code> for fresh workspaces.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Add host-scoped provider settings.</strong>
|
||
<div class="tiny">
|
||
Settings should answer “which GitHub/GitLab/Linear/Jira account is active on this
|
||
host?” without confusing client settings with server/SSH settings.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Gate UI by host capabilities and connection state.</strong>
|
||
<div class="tiny">
|
||
Remote Servers can expose runtime RPC capabilities. SSH hosts may support filesystem,
|
||
terminal, git, and provider CLI execution through Orca’s SSH bridge. Disconnected or
|
||
incompatible hosts should be visible but disabled where action would fail.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Extend CLI/API language to match the product model.</strong>
|
||
<div class="tiny">
|
||
Commands should accept <code>--project</code> plus <code>--host</code> or
|
||
<code>--project-host-setup</code> for workflows that create workspaces or automations.
|
||
Keep repo selectors as compatibility aliases.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Audit adjacent surfaces that already have host-specific state.</strong>
|
||
<div class="tiny">
|
||
Source-control AI model choices, task resume state, PR/review caches, setup scripts,
|
||
notification actions, direct launch-from-task flows, and run history should include
|
||
enough host identity to avoid cross-machine leakage.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Model</h2>
|
||
<div class="grid grid-3">
|
||
<div class="panel">
|
||
<div class="eyebrow">Host</div>
|
||
<h3>One user-facing bucket</h3>
|
||
<p class="tiny">
|
||
Local Mac, SSH target, Remote Server/runtime, and future Cloud VM all appear as
|
||
hosts. The user chooses where work runs; Orca chooses the transport.
|
||
</p>
|
||
</div>
|
||
<div class="panel">
|
||
<div class="eyebrow">Project setup</div>
|
||
<h3>Project on a host</h3>
|
||
<p class="tiny">
|
||
A logical project may have setup rows on multiple hosts. Each row owns path,
|
||
readiness, default worktree location, and setup method.
|
||
</p>
|
||
</div>
|
||
<div class="panel">
|
||
<div class="eyebrow">Provider identity</div>
|
||
<h3>Account where the request runs</h3>
|
||
<p class="tiny">
|
||
GitHub/GitLab/Linear/Jira identity should be explicit: local desktop account,
|
||
SSH-host CLI/token, or Remote Server account.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Tasks Mock</h2>
|
||
<div class="mock-shell" data-mock="tasks">
|
||
<div class="mock-titlebar">
|
||
<div class="window-dots"><span></span><span></span><span></span></div>
|
||
<div class="tiny">Tasks · provider context is visible</div>
|
||
<div class="tiny">⌘K</div>
|
||
</div>
|
||
<div class="mock-app">
|
||
<aside class="sidebar">
|
||
<div class="sidebar-header">Workspaces</div>
|
||
<div class="side-section-title">Local Mac</div>
|
||
<div class="side-row current">
|
||
<span class="dot online"></span>
|
||
<span>orca</span>
|
||
<span class="side-count">4</span>
|
||
</div>
|
||
<div class="side-section-title">openclaw 2</div>
|
||
<div class="side-row">
|
||
<span class="dot online"></span>
|
||
<span>orca</span>
|
||
<span class="side-count">2</span>
|
||
</div>
|
||
<div class="side-section-title">build-vm</div>
|
||
<div class="side-row">
|
||
<span class="dot warning"></span>
|
||
<span>orca</span>
|
||
<span class="side-count">auth</span>
|
||
</div>
|
||
</aside>
|
||
<section class="content">
|
||
<div class="toolbar">
|
||
<div class="toolbar-main">
|
||
<strong>Tasks</strong>
|
||
<div class="tabs" role="tablist">
|
||
<button class="tab active" data-tab-target="github">GitHub</button>
|
||
<button class="tab" data-tab-target="linear">Linear</button>
|
||
<button class="tab" data-tab-target="gitlab">GitLab</button>
|
||
</div>
|
||
</div>
|
||
<div class="toolbar-main">
|
||
<span class="select-like">Project: orca</span>
|
||
<span class="select-like" id="task-host-select">Host: Local Mac</span>
|
||
<span class="identity-pill"><span class="dot online"></span><span id="task-identity">GitHub: @jinwoo</span></span>
|
||
</div>
|
||
</div>
|
||
<div class="list" id="task-list-github">
|
||
<div class="task-row">
|
||
<div>
|
||
<div class="task-title">#5071 Review multi-host project setup flow</div>
|
||
<div class="meta-line">
|
||
<span>orca · GitHub</span>
|
||
<span>served by Local Mac</span>
|
||
<span>account @jinwoo</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Start on Local Mac</span>
|
||
</div>
|
||
<div class="task-row">
|
||
<div>
|
||
<div class="task-title">#5068 Add runtime compatibility copy</div>
|
||
<div class="meta-line">
|
||
<span>orca · GitHub</span>
|
||
<span>also available on openclaw 2</span>
|
||
<span>2 host contexts</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Choose host…</span>
|
||
</div>
|
||
<div class="notice">
|
||
Host context is a first-class filter. If openclaw 2 has a different GitHub
|
||
account, switching Host changes the request owner and the rows can legitimately differ.
|
||
</div>
|
||
</div>
|
||
<div class="list hidden" id="task-list-linear">
|
||
<div class="task-row">
|
||
<div>
|
||
<div class="task-title">ORC-1842 Confirm SSH add-project path polish</div>
|
||
<div class="meta-line">
|
||
<span>Linear</span>
|
||
<span>served by selected host</span>
|
||
<span>workspace Stably Eng</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Create workspace</span>
|
||
</div>
|
||
<div class="notice">
|
||
Linear/Jira should no longer use only the ambient active runtime. The Tasks page
|
||
should pass an explicit host context to provider clients.
|
||
</div>
|
||
</div>
|
||
<div class="list hidden" id="task-list-gitlab">
|
||
<div class="task-row">
|
||
<div>
|
||
<div class="task-title">!92 Remote relay health checks</div>
|
||
<div class="meta-line">
|
||
<span>GitLab</span>
|
||
<span>served by openclaw 2</span>
|
||
<span>glab on SSH host</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Start on openclaw 2</span>
|
||
</div>
|
||
<div class="notice">
|
||
GitLab should gain the same host request target as GitHub instead of being only a
|
||
desktop IPC call with SSH-aware path resolution.
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
<p class="mock-caption">
|
||
Interaction: click GitHub / Linear / GitLab above. The important UI addition is the
|
||
visible Host + provider identity pair, not a separate “remote task” mode.
|
||
</p>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Automations Mock</h2>
|
||
<div class="mock-shell" data-mock="automations">
|
||
<div class="mock-titlebar">
|
||
<div class="window-dots"><span></span><span></span><span></span></div>
|
||
<div class="tiny">Automation editor · run location is explicit</div>
|
||
<div></div>
|
||
</div>
|
||
<div class="split">
|
||
<section class="panel">
|
||
<div class="eyebrow">Create Automation</div>
|
||
<h3>Daily issue triage</h3>
|
||
<div class="form">
|
||
<div class="field">
|
||
<div class="label">Project</div>
|
||
<div class="select-like">orca</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">Run on</div>
|
||
<div class="input-row">
|
||
<span class="select-like">openclaw 2</span>
|
||
<span class="identity-pill"><span class="dot online"></span>SSH host</span>
|
||
</div>
|
||
<div class="tiny">
|
||
Only hosts where this project is set up appear here. Add Project remains the way
|
||
to make the project available on another host.
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">Workspace</div>
|
||
<div class="tabs">
|
||
<button class="tab active">New run</button>
|
||
<button class="tab">Existing worktree</button>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">Create from</div>
|
||
<div class="select-like">origin/main · resolved on openclaw 2</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">Agent</div>
|
||
<div class="select-like">Codex · model from openclaw 2 host settings</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="label">Provider context</div>
|
||
<div class="select-like">GitHub tasks: @deploy-bot on openclaw 2</div>
|
||
</div>
|
||
<div class="notice">
|
||
Stored target should be logical project + host setup. Existing workspace mode can
|
||
infer host from the workspace, but the editor should still display it.
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="panel">
|
||
<div class="eyebrow">Run history</div>
|
||
<div class="automation-row">
|
||
<div>
|
||
<div class="automation-title">Daily issue triage</div>
|
||
<div class="meta-line">
|
||
<span>orca</span>
|
||
<span>openclaw 2</span>
|
||
<span>auto-daily-20260612</span>
|
||
</div>
|
||
</div>
|
||
<span class="status"><span class="dot online"></span>Completed</span>
|
||
</div>
|
||
<div class="automation-row">
|
||
<div>
|
||
<div class="automation-title">Daily issue triage</div>
|
||
<div class="meta-line">
|
||
<span>orca</span>
|
||
<span>build-vm</span>
|
||
<span>interactive SSH auth needed</span>
|
||
</div>
|
||
</div>
|
||
<span class="status"><span class="dot warning"></span>Skipped</span>
|
||
</div>
|
||
<div class="notice">
|
||
Scheduled runs should preserve host and workspace display names so history remains
|
||
understandable after a host disconnects or a workspace is deleted.
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Settings Mock</h2>
|
||
<div class="mock-shell" data-mock="settings">
|
||
<div class="mock-titlebar">
|
||
<div class="window-dots"><span></span><span></span><span></span></div>
|
||
<div class="tiny">Settings · host-scoped integrations</div>
|
||
<div></div>
|
||
</div>
|
||
<div class="mock-app">
|
||
<aside class="sidebar">
|
||
<div class="sidebar-header">Settings</div>
|
||
<div class="side-row current"><span>⌁</span><span>Hosts</span><span></span></div>
|
||
<div class="side-row"><span>○</span><span>Integrations</span><span></span></div>
|
||
<div class="side-row"><span>◇</span><span>Agents</span><span></span></div>
|
||
<div class="side-row"><span>□</span><span>Projects</span><span></span></div>
|
||
</aside>
|
||
<section class="content">
|
||
<div class="toolbar">
|
||
<div>
|
||
<strong>Host Settings</strong>
|
||
<div class="tiny">Settings that depend on where commands run</div>
|
||
</div>
|
||
<span class="select-like">Viewing: openclaw 2</span>
|
||
</div>
|
||
<div class="list">
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="task-title">GitHub</div>
|
||
<div class="meta-line">
|
||
<span>Account @deploy-bot</span>
|
||
<span>Served through SSH host CLI/token</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Reconnect</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="task-title">GitLab</div>
|
||
<div class="meta-line">
|
||
<span>Not connected on this host</span>
|
||
<span>Tasks will be disabled for GitLab on openclaw 2</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Connect</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<div>
|
||
<div class="task-title">Default worktree location</div>
|
||
<div class="meta-line">
|
||
<span><code>~/orca/worktrees</code></span>
|
||
<span>Host filesystem path</span>
|
||
</div>
|
||
</div>
|
||
<span class="button-like">Change</span>
|
||
</div>
|
||
<div class="notice">
|
||
This does not need to become a huge second Settings app. Keep global client
|
||
preferences global, and add a host dropdown only on panes whose values truly live
|
||
on the selected host.
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Implementation Breakdown</h2>
|
||
<div class="table">
|
||
<div class="table-row table-head">
|
||
<div>Area</div>
|
||
<div>Change</div>
|
||
<div>Verification</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Shared model</div>
|
||
<div>
|
||
Add a normalized provider runtime target keyed by <code>ExecutionHostId</code>. Keep
|
||
existing <code>ProjectHostSetup</code> as the project-on-host record.
|
||
</div>
|
||
<div>Unit tests for local, SSH, runtime, disconnected, old-runtime.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>GitHub Tasks</div>
|
||
<div>
|
||
Route SSH GitHub lookups through the selected SSH host when supported, or clearly
|
||
label them as desktop-served until support lands.
|
||
</div>
|
||
<div>Local account vs SSH account fixture must return different rows.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>GitLab Tasks</div>
|
||
<div>
|
||
Move from desktop-only IPC assumptions to explicit host provider target. Preserve
|
||
current SSH project-ref safeguards.
|
||
</div>
|
||
<div>GitLab local, SSH, and runtime provider smoke tests.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Linear / Jira</div>
|
||
<div>
|
||
Replace ambient active-runtime routing in task surfaces with an explicit host context.
|
||
Settings can still default to the focused host.
|
||
</div>
|
||
<div>Switch host without changing project; account/status updates predictably.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Automations schema</div>
|
||
<div>
|
||
Add logical <code>projectId</code>, <code>hostId</code>, and optional
|
||
<code>projectHostSetupId</code>. Migrate old repo-id automations by mapping the repo
|
||
to its project-host setup.
|
||
</div>
|
||
<div>Migration tests with old repo-backed automations.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Automation dispatch</div>
|
||
<div>
|
||
Resolve host before precheck, worktree creation, terminal launch, provider session
|
||
observation, and usage collection.
|
||
</div>
|
||
<div>Scheduled run on local, SSH, runtime; disconnected SSH skip; auth-needed skip.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>CLI</div>
|
||
<div>
|
||
Add host-aware selectors for automation create/run and worktree creation while keeping
|
||
repo selectors compatible.
|
||
</div>
|
||
<div>CLI fixtures for <code>--project</code>, <code>--host</code>, old <code>--repo</code>.</div>
|
||
</div>
|
||
<div class="table-row">
|
||
<div>Telemetry / logs</div>
|
||
<div>
|
||
Track host kind and capability state, not hostnames, paths, repo names, or account
|
||
identifiers.
|
||
</div>
|
||
<div>Telemetry product gate review.</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Other Explicitness Gaps</h2>
|
||
<div class="checklist">
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Composer “Start from” and linked-work-item picker.</strong>
|
||
<div class="tiny">
|
||
The composer can fetch/link GitHub work items from the selected repo. In the new
|
||
model it should inherit or show the task source host/account, then choose a separate
|
||
run host when creating the workspace.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Task row actions and issue/PR drawers.</strong>
|
||
<div class="tiny">
|
||
Mutations such as assign, comment, review-request, state change, merge, mark viewed,
|
||
and create issue need to run under the same explicit provider context that fetched
|
||
the row, not whichever host is currently focused later.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Linear/Jira issue preview pages.</strong>
|
||
<div class="tiny">
|
||
These currently key heavily off active runtime and provider workspace ids. They need
|
||
a durable source host/account context so opening, editing, commenting, and starting a
|
||
workspace from an issue stay in the same provider identity.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P0</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Hosted review / PR helper flows.</strong>
|
||
<div class="tiny">
|
||
Review creation, PR field generation, fix-checks launch, branch-to-PR lookup, and
|
||
direct launch from review/task need to carry project-host setup plus provider source
|
||
context. Otherwise the action can resolve against the wrong checkout or account.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Settings and integrations entry points.</strong>
|
||
<div class="tiny">
|
||
Provider settings should say whether they are client-global, host-scoped, or
|
||
project-scoped. Opening settings from Tasks should land on the same host/account
|
||
context the user was just looking at.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Persisted task UI state and caches.</strong>
|
||
<div class="tiny">
|
||
Recent selections, resume state, work item cache keys, PR detail caches, labels,
|
||
assignees, and partial-failure banners should be keyed by provider source context,
|
||
not only repo id or active runtime.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Automation run history, reuse, and usage attribution.</strong>
|
||
<div class="tiny">
|
||
Runs should store logical project, project-host setup, source provider context, run
|
||
host, terminal/session ids, and display labels so history remains clear after host
|
||
disconnects, account changes, or workspace deletion.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>CLI/API selectors.</strong>
|
||
<div class="tiny">
|
||
CLI commands that create workspaces, create automations, start from tasks, or fetch
|
||
provider data need explicit <code>--project</code>, <code>--host</code>, and/or
|
||
<code>--task-source-host</code> options. Existing <code>--repo</code> selectors can
|
||
remain compatibility aliases.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P1</span>
|
||
</div>
|
||
<div class="check-row">
|
||
<span class="box">□</span>
|
||
<div>
|
||
<strong>Telemetry and diagnostics.</strong>
|
||
<div class="tiny">
|
||
Events/logs should include non-sensitive host kind and capability status so we can
|
||
debug routing without recording account names, hostnames, repo paths, or issue text.
|
||
</div>
|
||
</div>
|
||
<span class="priority">P2</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Subagent Audit Confirmation</h2>
|
||
<div class="callout">
|
||
<p>
|
||
A second codebase pass split across Tasks/provider routing, Automations,
|
||
Composer/PR launch, and Settings/cache/CLI agreed on the same core gap:
|
||
Orca needs an explicit <code>TaskSourceContext</code> separate from the
|
||
<code>ProjectHostSetup</code> used to run work.
|
||
</p>
|
||
</div>
|
||
<div class="grid grid-2">
|
||
<div class="panel compact">
|
||
<h4>Tasks/provider routing</h4>
|
||
<p class="tiny">
|
||
GitHub is partly host-scoped already, but Linear/Jira still route through active
|
||
runtime, GitLab is mostly repo-path/local-IPC based, and drawer mutations can lose the
|
||
source account. Report: <code>notes/subagent-tasks-provider-hosts-audit.md</code>.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Automations</h4>
|
||
<p class="tiny">
|
||
Automations still treat <code>projectId</code> as a repo id and do not snapshot
|
||
<code>hostId</code>, <code>projectHostSetupId</code>, provider source context, or
|
||
runtime capability/version on runs. Report:
|
||
<code>notes/subagent-automations-host-model-audit.md</code>.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Composer / PR launch</h4>
|
||
<p class="tiny">
|
||
Start-from flows use one <code>repoId</code> as both source item and run target.
|
||
Pending worktree creation stores linked numbers but not source host/account context.
|
||
Report: <code>notes/subagent-composer-pr-launch-hosts-audit.md</code>.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Settings / cache / CLI</h4>
|
||
<p class="tiny">
|
||
Some host foundations are strong, but GitLab selectors are repo-path-only, provider
|
||
diagnostics are still client-global, agent launch overrides are global, and CLI
|
||
automation selectors remain repo-first. Report:
|
||
<code>notes/subagent-settings-cache-cli-hosts-audit.md</code>.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Open Product Decisions</h2>
|
||
<div class="grid grid-2">
|
||
<div class="panel compact">
|
||
<h4>Do Tasks allow multi-host aggregation?</h4>
|
||
<p class="tiny">
|
||
Recommendation: yes for GitHub/GitLab rows when each row can show its serving host,
|
||
but default to one selected host for Linear/Jira until cross-host grouping is useful.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Should SSH provider auth run on the SSH machine?</h4>
|
||
<p class="tiny">
|
||
Recommendation: eventually yes. In the interim, label desktop-served SSH provider
|
||
calls explicitly to avoid misleading users with different accounts.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Are Remote Servers “better SSH”?</h4>
|
||
<p class="tiny">
|
||
Recommendation: explain them as richer hosts. SSH gives filesystem/terminal access to
|
||
a machine you already manage. Remote Server adds Orca runtime services, durable RPC,
|
||
web/mobile handoff, capability/version negotiation, and richer background behavior.
|
||
</p>
|
||
</div>
|
||
<div class="panel compact">
|
||
<h4>Do we need host onboarding now?</h4>
|
||
<p class="tiny">
|
||
Recommendation: no. Existing SSH/server settings can remain the entry point. This work
|
||
should make configured hosts behave correctly once present.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
<script>
|
||
const tabs = document.querySelectorAll('[data-tab-target]');
|
||
const lists = {
|
||
github: document.getElementById('task-list-github'),
|
||
linear: document.getElementById('task-list-linear'),
|
||
gitlab: document.getElementById('task-list-gitlab')
|
||
};
|
||
const identity = document.getElementById('task-identity');
|
||
const host = document.getElementById('task-host-select');
|
||
const labels = {
|
||
github: ['Host: Local Mac', 'GitHub: @jinwoo'],
|
||
linear: ['Host: openclaw 2', 'Linear: Stably Eng on openclaw 2'],
|
||
gitlab: ['Host: openclaw 2', 'GitLab: glab on openclaw 2']
|
||
};
|
||
|
||
tabs.forEach((tab) => {
|
||
tab.addEventListener('click', () => {
|
||
const key = tab.dataset.tabTarget;
|
||
tabs.forEach((candidate) => candidate.classList.toggle('active', candidate === tab));
|
||
Object.entries(lists).forEach(([name, node]) => {
|
||
node.classList.toggle('hidden', name !== key);
|
||
});
|
||
host.textContent = labels[key][0];
|
||
identity.textContent = labels[key][1];
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|