# Worktree & Parallel Agent Orchestration

> How Orca creates, tracks, and tears down isolated git worktrees for each agent session; the agent-awake service, trust presets, hook lifecycle, worktree-removal safety checks, and the IPC surface that the renderer uses to drive orchestration.

- Repository: stablyai/orca
- GitHub: https://github.com/stablyai/orca
- Human wiki: https://grok-wiki.com/public/wiki/stablyai-orca-47ffb1f68457
- Complete Markdown: https://grok-wiki.com/public/wiki/stablyai-orca-47ffb1f68457/llms-full.txt

## Source Files

- `src/main/repo-worktrees.ts`
- `src/main/worktree-removal-safety.ts`
- `src/main/agent-awake-service.ts`
- `src/main/agent-trust-presets.ts`
- `src/main/hooks.ts`
- `src/main/ipc/worktrees.ts`
- `src/shared/worktree-id.ts`
- `src/shared/workspace-session-schema.ts`
- `src/shared/agents-orchestration-steps.ts`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [src/main/repo-worktrees.ts](src/main/repo-worktrees.ts)
- [src/main/worktree-removal-safety.ts](src/main/worktree-removal-safety.ts)
- [src/main/agent-awake-service.ts](src/main/agent-awake-service.ts)
- [src/main/agent-trust-presets.ts](src/main/agent-trust-presets.ts)
- [src/main/hooks.ts](src/main/hooks.ts)
- [src/main/ipc/worktrees.ts](src/main/ipc/worktrees.ts)
- [src/main/ipc/worktree-remote.ts](src/main/ipc/worktree-remote.ts)
- [src/main/worktree-orphan-gitdir-proof.ts](src/main/worktree-orphan-gitdir-proof.ts)
- [src/shared/worktree-id.ts](src/shared/worktree-id.ts)
- [src/shared/workspace-session-schema.ts](src/shared/workspace-session-schema.ts)
- [src/shared/agents-orchestration-steps.ts](src/shared/agents-orchestration-steps.ts)
</details>

# Worktree & Parallel Agent Orchestration

Orca models each agent session as an isolated git worktree. Every workspace the user opens or creates maps to one linked worktree directory — a full checkout of a separate branch that shares the `.git` object store with the repository's primary worktree. This design lets multiple AI agents run concurrently without touching each other's working files.

This page covers the full lifecycle: how worktree identities are encoded, how listings fan out across local and SSH repos, the safety checks that guard removal, the agent-awake service that prevents the OS from suspending while agents are active, the trust-preset mechanism that bypasses agent startup prompts, the hook system that runs setup and teardown scripts, and the Electron IPC surface that ties the renderer's orchestration UI to the main-process backend.

---

## Worktree Identity

Every worktree in Orca is referenced by a **worktree ID** — a stable compound string of the form:

```
{repoId}::{worktreePath}
```

The `::` separator (exported as `WORKTREE_ID_SEPARATOR`) lets callers split the ID without knowing the platform path separator. Folder-mode repos, which have no linked-worktree graph, use a richer identity to support multiple concurrent workspace sessions inside the same directory:

```
{repoId}::{folderPath}::workspace:{uuid}
```

The `FOLDER_WORKSPACE_INSTANCE_SEPARATOR` constant (`::workspace:`) marks the boundary between the real filesystem path and the per-session UUID. `splitWorktreeIdForFilesystem` strips the UUID suffix so callers that need a CWD still get the real folder path.

Sources: [src/shared/worktree-id.ts:1-50]()

---

## Worktree Listing

`listRepoWorktrees` in `src/main/repo-worktrees.ts` is the authoritative entry point for enumerating a repo's worktrees at runtime. It dispatches across three modes:

| Repo mode | Resolved worktrees |
|---|---|
| **Folder** | Returns a single synthetic `GitWorktreeInfo` with `isMainWorktree: true`; no git call is made |
| **SSH** | Delegates to the SSH git provider; returns `[]` if the provider hasn't yet reattached during startup |
| **Local git** | Calls `listWorktrees(repo.path)` which runs `git worktree list` |

The folder branch creates a stub so Orca's worktree-first UI has a single stable workspace identity even when there is no linked-worktree graph.

Sources: [src/main/repo-worktrees.ts:1-40]()

---

## IPC Surface

The renderer communicates with the main process exclusively through Electron IPC. All worktree handlers are wired in `registerWorktreeHandlers` (`src/main/ipc/worktrees.ts`). Previous handlers are removed before re-registration so macOS window recreation does not accumulate duplicates.

### Handler catalogue

| IPC channel | Description |
|---|---|
| `worktrees:listAll` | Lists visible worktrees for all repos in parallel |
| `worktrees:list` | Lists visible worktrees for a single repo |
| `worktrees:listDetected` | Returns full `DetectedWorktree` data including visibility & ownership |
| `worktrees:create` | Creates a local, remote, or folder workspace |
| `worktrees:resolvePrBase` | Resolves the Git base for a GitHub PR |
| `worktrees:resolveMrBase` | Resolves the Git base for a GitLab MR |
| `worktrees:remove` | Runs archive hook, tears down PTYs, then removes the worktree |
| `worktrees:updateMeta` | Persists metadata changes without notifying other subscribers |
| `worktrees:listLineage` | Returns the full parent→child lineage map |
| `worktrees:updateLineage` | Reassigns a workspace's parent worktree |
| `worktrees:persistSortOrder` | Batch-stamps descending `sortOrder` timestamps for sidebar ordering |
| `hooks:check` | Reads and parses `orca.yaml`, flags unrecognized top-level keys |
| `hooks:createIssueCommandRunner` | Writes a platform-appropriate runner script for issue automation |
| `hooks:inspectSetupScriptImports` | Inspects candidate setup-script import files |
| `hooks:readIssueCommand` | Reads the local `.orca/issue-command` override and/or shared YAML command |
| `hooks:writeIssueCommand` | Writes or clears the per-user issue command override |

### Parallel listing

`worktrees:listAll` issues `listRepoWorktrees` for all repos concurrently with `Promise.all`, so the total latency is bounded by the slowest single repo rather than by the sum of all repos.

Sources: [src/main/ipc/worktrees.ts:343-380]()

### Concurrent removal deduplication

Double-clicks, stale toast actions, and sidebar races can all target the same worktree for removal simultaneously. The handler keeps a `worktreeRemovalsInFlight` map keyed by `worktreeId`. When a second call arrives with the same `optionsKey` (force/skipArchive combination), it receives the existing promise. A different `optionsKey` (e.g., normal then force) throws immediately.

Sources: [src/main/ipc/worktrees.ts:595-620]()

---

## Worktree Creation Flow

Creation dispatches to one of three helpers depending on repo mode:

```text
worktrees:create
    ├─ isFolderRepo  →  createFolderWorkspace()    (metadata only, no git)
    ├─ repo.connectionId  →  createRemoteWorktree() (via SSH git provider)
    └─ local          →  createLocalWorktree()      (git worktree add + hooks)
```

After a successful create, Orca:
1. Stamps provenance metadata (`orcaCreatedAt`, `orcaCreationSource: 'desktop'`) into the store.
2. Optionally runs the `setup` hook inside the new worktree directory.
3. Emits a `workspace_created` telemetry event.
4. Calls `notifyWorktreesChanged` to push a refresh to the renderer.

Sources: [src/main/ipc/worktrees.ts:430-495]()

---

## Worktree Removal Safety

`src/main/worktree-removal-safety.ts` provides layered protection before any destructive filesystem operation.

### Path-level guards

`isDangerousWorktreeRemovalPath` returns `true` (blocking removal) for:

- Empty or whitespace-only paths
- A path equal to the repository root
- A path that is the filesystem root (e.g., `/` or `C:\`)
- A path that **contains** the repository root (i.e., the repo is nested inside the target)
- A path that **contains** the user's home directory (`os.homedir()`)

Platform-aware path operations (`posix` vs `win32`) are selected based on whether any path looks like a Windows absolute path. This ensures Windows UNC paths routed through WSL work correctly.

Sources: [src/main/worktree-removal-safety.ts:43-73]()

### Git-registration guards

`findRegisteredDeletableWorktree` confirms that:
1. The requested path is registered in `git worktree list`.
2. The worktree is not `isMainWorktree`.
3. The path passes `isDangerousWorktreeRemovalPath`.
4. No other registered worktree lives **inside** the target path.

The last check protects against `git worktree remove --force` treating a nested linked worktree's working files as untracked directories.

Sources: [src/main/worktree-removal-safety.ts:75-112]()

### Orphaned directory proof

When a worktree directory exists on disk but is no longer registered with Git, `canSafelyRemoveOrphanedWorktreeDirectory` uses `gitFileProvesOrphanedWorktreeDirectory` (in `worktree-orphan-gitdir-proof.ts`) to confirm the directory's `.git` file actually points into this repo's `.git/worktrees/<name>` admin directory — and that the admin entry's back-reference (`gitdir` file) resolves back to the candidate. Only if both ends of the link match is the directory safe to remove recursively.

### Orca-provenance cleanup eligibility

`canCleanupUnregisteredOrcaWorktreeDirectory` decides whether an unregistered directory can be cleaned up by checking:

1. **Current provenance**: `orcaCreatedAt` + `orcaCreationSource` ∈ `{desktop, runtime, cli, ssh}`.
2. **Legacy evidence**: presence of `createdAt`, `createdWithAgent`, `pushTarget`, `sparseBaseRef`, `sparsePresetId`, or `preserveBranchOnDelete`.
3. **Path shape**: matches the `workspaceDir/<repo>/<name>` structure Orca used before explicit provenance was added.

Sources: [src/main/worktree-removal-safety.ts:120-165]()

### Removal sequence

```mermaid
stateDiagram-v2
    [*] --> PathSafetyCheck
    PathSafetyCheck --> GitRegistrationCheck : path is safe
    PathSafetyCheck --> Blocked : dangerous path
    GitRegistrationCheck --> ArchiveHook : registered & deletable
    GitRegistrationCheck --> OrphanProof : not in git list
    OrphanProof --> OrphanCleanup : .git file proves orphan + force flag
    OrphanProof --> Blocked : cannot prove orphan
    ArchiveHook --> PTYTeardown : hook completed (or skipped)
    PTYTeardown --> GitRemove : PTYs killed
    GitRemove --> MetaCleanup : git worktree remove
    GitRemove --> PruneThenClean : orphaned worktree error
    OrphanCleanup --> MetaCleanup
    PruneThenClean --> MetaCleanup
    MetaCleanup --> [*] : notifyWorktreesChanged
    Blocked --> [*] : throws error
```

---

## Agent-Awake Service

`AgentAwakeService` (`src/main/agent-awake-service.ts`) prevents the OS from sleeping or suspending the application while one or more agents are actively working.

### Architecture

The service is cross-platform and uses three independent mechanisms simultaneously:

| Mechanism | Platform | Implementation |
|---|---|---|
| `powerSaveBlocker.start('prevent-display-sleep')` | All (Electron) | Blocks display sleep; must call `isStarted()` to reconcile after OS resumes |
| `MacosSystemSleepAssertion` | macOS | Platform sleep assertion via native API |
| `LinuxLidSleepAssertion` | Linux | Lid-close inhibitor lock |

Windows lid-close is intentionally omitted because keeping the machine awake across a lid close requires mutating the user's global power plan.

### Wake eligibility

A status record is considered wake-eligible only when all three conditions hold:
- `state === 'working'`
- `observedInCurrentRuntime === true` (guards against stale status from a prior Electron launch)
- `receivedAt` is within the last **2 hours** (`AGENT_AWAKE_STATUS_STALE_AFTER_MS = 2 * 60 * 60 * 1000`)

A `setTimeout` is scheduled for the earliest impending staleness expiry. When no timer is relevant, no timer is set. The timer is `unref()`'d so it does not prevent Node.js from exiting.

On OS resume (`powerMonitor 'resume'` event), the service calls `refresh('power-resume')` to re-evaluate and re-acquire any blockers the OS may have dropped during sleep.

Sources: [src/main/agent-awake-service.ts:22-30](), [src/main/agent-awake-service.ts:107-125]()

---

## Trust Presets

Before an agent TUI launches in a new worktree, Orca pre-writes the same trust artifacts that the agent CLI writes after the user manually accepts a "Do you trust this folder?" prompt. Without this, Orca's URL injection (injected via bracketed paste once the TUI is up) would be intercepted by single-character menu reads and would either select a random option or quit the session.

| Agent | Trust artifact location | Format |
|---|---|---|
| **Cursor** | `~/.cursor/projects/<slug>/.workspace-trusted` | `{ trustedAt, workspacePath }` JSON |
| **Copilot** | `~/.copilot/config.json` → `trustedFolders[]` | Appended path string |
| **Codex** | `~/.codex/config.toml` + Orca-managed `CODEX_HOME/config.toml` | `[projects."<path>"] trust_level = "trusted"` |

All three functions resolve the worktree path through `realpathSync` before any comparison or write, because macOS reports `/tmp/x` and `/private/tmp/x` as the same inode but agent trust comparators use `realpath()` during lookup.

Sources: [src/main/agent-trust-presets.ts:1-55]()

For Codex, the trust is written to **both** `~/.codex/config.toml` and the Orca-managed `CODEX_HOME` config because Orca launches Codex with its own `CODEX_HOME` environment, and both paths must agree.

Sources: [src/main/agent-trust-presets.ts:90-100]()

---

## Hook Lifecycle

Orca reads hooks from `orca.yaml` in the repository root (committed, project-wide defaults) and from `.orca/issue-command` (per-user local override, gitignored). The `orca.yaml` schema supports two top-level keys:

```yaml
scripts:
  setup: |
    npm install
    npm run build
  archive: |
    echo "Cleaning up..."
issueCommand: gh issue view $ISSUE_NUMBER
```

### Hook execution at creation

When a worktree is created, `shouldRunSetupForCreate` consults the repo's `setupRunPolicy` (`run-by-default`, `ask`, or manual `decision` argument). If setup should run, Orca:
1. Calls `createSetupRunnerScript` to write a platform runner script into the worktree's git storage path (`git rev-parse --git-path orca/setup-runner.sh`).
2. Sets env vars: `ORCA_ROOT_PATH`, `ORCA_WORKTREE_PATH`, `ORCA_WORKSPACE_NAME`, plus legacy `CONDUCTOR_ROOT_PATH` and `GHOSTX_ROOT_PATH` aliases.
3. On WSL worktrees, path-translates all env var values from Windows UNC to Linux paths.

The runner script is written in Bash (`#!/usr/bin/env bash\nset -e`) on POSIX/WSL and in a `@echo off` + `call <cmd>` / `if errorlevel 1 exit /b` pattern on native Windows so multi-line scripts fail fast, matching `set -e` semantics.

Sources: [src/main/hooks.ts:262-320]()

### Hook execution at removal

Before `git worktree remove` runs, the IPC handler calls `runHook('archive', canonicalWorktreePath, repo)`. On SSH repos, the archive script is forwarded to `provider.execNonInteractive(...)` with a 2-minute timeout. Failure is logged but does not abort the removal.

### Source policy

`resolveHookCommandSourcePolicy` merges the committed `scripts:` block with the local Settings override according to three modes:

| Policy | Behavior |
|---|---|
| `local-only` | Only the per-user Settings script runs |
| `run-both` | Committed script + local script are concatenated, committed first |
| _(default)_ | Committed YAML script is authoritative; local script is ignored |

### Issue command

The issue command is resolved via `readIssueCommand`: the local `.orca/issue-command` file takes precedence over `issueCommand:` in `orca.yaml`. `writeIssueCommand` creates `.orca/` on first write and ensures it appears in `.gitignore`.

Sources: [src/main/hooks.ts:160-195]()

---

## Session State Schema

Workspace UI state (active tabs, terminal layouts, open editors, browser workspaces) is persisted on shutdown and restored on next launch. The schema is validated with Zod at the read boundary via `parseWorkspaceSession`, which returns a discriminated union `{ ok: true, value }` or `{ ok: false, error }` so callers can fall back to defaults without a try/catch.

The schema is intentionally **tolerant of extra fields** (additive forward compatibility) but strict on the types of fields it reads. A single corrupted field (e.g., `NaN` in `lastVisitedAtByWorktreeId`) is stripped rather than failing the entire session, keeping the blast radius small.

Sources: [src/shared/workspace-session-schema.ts:1-30](), [src/shared/workspace-session-schema.ts:205-240]()

---

## Orchestration UI Model

`AGENTS_STEPS` in `src/shared/agents-orchestration-steps.ts` defines the three informational steps shown in Orca's "Explore Orca" onboarding modal:

| Step ID | Name | Role |
|---|---|---|
| `statuses` | Visibility | Shows which agents are working, waiting, live, or blocked |
| `orchestration` | Orchestration | Explains how agents can manage and coordinate workspaces |
| `usage` | Usage *(optional)* | API usage and rate-limit monitoring across connected accounts |

These steps are UI copy; the orchestration engine itself lives in the IPC and runtime layers described above.

---

## Data Flow Summary

```text
Renderer (React)
  │  worktrees:create / worktrees:remove / worktrees:listAll
  ▼
registerWorktreeHandlers   (src/main/ipc/worktrees.ts)
  ├─ listRepoWorktrees      → git worktree list  /  SSH provider  /  folder stub
  ├─ worktree-removal-safety → isDangerousPath, git registration, orphan proof
  ├─ hooks (orca.yaml)      → setup runner  /  archive hook  /  issue-command
  ├─ agent-trust-presets    → Cursor / Copilot / Codex trust files
  └─ AgentAwakeService      → Electron powerSaveBlocker + macOS/Linux assertions
```

Each worktree that Orca creates carries:
- A stable `{repoId}::{worktreePath}` identity used by PTY sessions, tabs, editors, and browsers.
- `WorktreeMeta` persisted in the store with provenance fields (`orcaCreatedAt`, `orcaCreationSource`) that gate safe cleanup later.
- Platform-specific runner scripts written into the git storage directory so setup and teardown commands do not depend on the renderer remaining open.

When agents finish and worktrees are removed, the archive hook runs first, PTY processes are killed, git deregisters the worktree, and the store prunes the metadata — leaving no stale git locks or dangling session state.
