# Project Isolation Execution Design
Date: 2026-04-01
Status: Core execution chain, cloud-owned inventory, bundle freshness hardening, replacement/rollback hardening, broader churn coverage, and lifecycle smoke are implemented

## 1. Scope and product constraints
This document describes the current desktop implementation for project-isolated execution.
Confirmed product constraints:
- Project inventory is fixed by backend configuration.
- Projects currently come from `openclaw-employee-config`.
- The active bundle source is `skills[].skill.download_url`.
- `project_bundle_url` is not part of the current implementation.
- Local project CRUD is not part of the target product shape.
- The current backend contract returns a `skills` array.
- Each `skills[]` object currently treats `skill.download_url` as one project zip URL.
- Multiple projects are represented by multiple `skills[]` objects.
- Any future multi-value download URL contract must be handled as a separate compatibility change.

## 2. Implemented architecture
The implemented chain is:
1. Runtime cloud bootstrap or payload sync triggers project bundle sync.
2. Remote zip bundles are discovered from `skills[].skill.download_url`, downloaded, and extracted.
3. Bundle content is materialized into local project roots plus shared `skills/` and `cron/` content.
4. Materialized projects are registered in local project metadata.
5. Empty inventory does not recreate a local fallback project; chat session creation waits for the first cloud-backed project.
6. Sessions are bound to projects through `ProjectStoreService`.
7. `ProjectContextService` builds and caches project snapshots from `SOUL.md`, `USER.md`, `README.md`, and tracked memory files.
8. `ProjectExecutionRouter` routes each request to one of:
   - `workspace-entry`
   - `skill`
   - `chat-fallback`
9. `ipc.ts` prepares each request against the session's project snapshot before execution.
10. Bundle reconciliation removes stale bundle-managed projects, shared `skills/` entries, shared `cron/` entries, and stale manifest records when the expected cloud bundle set changes.
11. Bundle freshness probes the remote bundle with HTTP metadata before deciding whether an existing local materialization can be reused.
12. Same-`projectId` replacement now stages project/shared assets, commits them in order, and either finalizes or rolls back the whole replacement set.
13. Broader churn coverage now verifies survivor, replacement, removal, and addition flows across multiple projects without changing the current cloud protocol.

## 3. Code-truth execution behavior
Current behavior verified from code:
- `workspace-entry` executes inside the isolated project root.
- `skill` routing uses project skill binding and runtime skill bridge prompt preparation.
- `chat-fallback` also receives injected project context and stays project-bound.
- Session to project binding is real.
- Session to snapshot binding is real.
- Project context injection is real.
- Cloud zip sync is real.
- Empty inventory semantics are real.
- Stale bundle reconciliation is real for bundle-managed project and shared asset cleanup.
- Bundle freshness hardening is real.
- Replacement / rollback hardening is real for same-project bundle updates.

Default chat refresh semantics are explicit in code:
- `apps/desktop/src/main/services/project-context-lifecycle.ts` defines shared post-execution refresh behavior.
- `chat-fallback`, `skill`, and `workspace-entry` all schedule post-execution project context refresh.
- The refresh is asynchronous and does not block reply delivery.
- When refresh succeeds, `session.contextSnapshotId` is rebound to the refreshed snapshot.
- The next request reuses the refreshed snapshot instead of discovering it lazily.

Bundle freshness semantics are explicit in code:
- Reuse is no longer based only on `sourceUrl + configVersion`.
- If a manifest record is reusable, the app sends a `HEAD` probe before skipping reinstall.
- The probe records `ETag`, `Last-Modified`, and `Content-Length` when available.
- If remote freshness identity changes, the bundle is re-downloaded and re-materialized.
- If an older manifest has no freshness identity but the remote now exposes one, one re-download is forced to establish the baseline.

Bundle replacement semantics are explicit in code:
- bundle install follows `stage -> commit -> finalize/rollback`
- project root and shared `skills/` / `cron/` content are treated as one replacement transaction
- if metadata sync fails after commit, the previous project root and shared assets are restored
- the next sync can recover cleanly and persist the new manifest ownership

## 4. Verified smoke coverage
Current smoke coverage in the repo:
- `workspace-entry-smoke.ps1`
  - validates workspace-entry execution inside an isolated project
- `cloud-bundle-smoke.ps1`
  - validates cloud zip to bundle sync to active project to workspace-entry
  - covers payload `sync`
  - covers cached `init`
  - covers same-`projectId` replacement through the Electron UI/main flow
- `project-context-refresh-smoke.ps1`
  - validates snapshot cache, invalidation, refresh, and session snapshot rebinding
- `default-chat-smoke.ps1`
  - validates `chat-fallback` routing
  - validates project context injection into the prepared prompt
  - validates post-execution snapshot refresh
  - validates session snapshot rebinding
  - validates reuse of the refreshed snapshot on the next request
- `project-empty-inventory-smoke.ps1`
  - validates no-project inventory stays empty
  - validates session listing returns `[]`
  - validates session creation is blocked until cloud bundle sync completes
- `project-bundle-reconcile-smoke.ps1`
  - validates stale bundle project removal
  - validates shared `skills/` cleanup
  - validates shared `cron/` cleanup
  - validates manifest pruning
  - validates active-project fallback after cleanup
- `project-bundle-freshness-smoke.ps1`
  - validates re-download when `ETag` / `Last-Modified` change at the same download URL
  - validates persisted freshness metadata in bundle manifest
- `project-bundle-replacement-smoke.ps1`
  - validates same-project replacement at the service layer
  - validates rollback after injected post-commit failure
  - validates successful recovery on the next sync
- `project-bundle-churn-smoke.ps1`
  - validates multi-project survivor behavior
  - validates same-project replacement during broader churn
  - validates project removal and project addition in the same sync window
  - validates active-project fallback when the active project is removed
  - validates session survival inside unaffected projects
- `project-isolation-smoke.ps1`
  - aggregates the main project-isolation regression smokes
  - now includes reconcile, freshness, replacement, and churn service-level coverage

Electron smoke validation is also stronger now:
- workspace-entry validation no longer assumes the final status label must contain `workspace`
- smoke state records status label history and validates that a workspace-agent phase actually occurred
- smoke action selection now follows the active project session instead of assuming a stable pre-replacement session id

## 5. What is still incomplete
The earlier core gaps are closed.
The main follow-up areas now are:
- deciding whether the `project-isolation-smoke.ps1` and `cloud-bundle-smoke.ps1` gate pair should be wired into broader external CI / release coverage
- expanding deterministic churn coverage into larger or randomized stress matrices only when product changes raise the risk level
- keeping related product and rollout docs aligned with the implementation
- implementing any future protocol migration away from single `skills[].skill.download_url` only when backend is ready

## 6. Recommended next implementation order
1. Keep the current project-isolation smoke set green.
2. Use `project-isolation-smoke.ps1` plus `cloud-bundle-smoke.ps1` as the default higher-level regression gate pair.
3. Expand breadth only when new isolation surfaces or larger multi-project behaviors are introduced.
4. Handle any future `download_url` protocol evolution as a dedicated compatibility task.

## 7. Bottom line
Current status:
- The core project isolation chain is implemented.
- Session and project binding are implemented.
- Cloud-owned inventory enforcement is implemented.
- Project context injection is implemented.
- Cloud zip sync is implemented.
- Default chat refresh is aligned with other project-aware execution paths.
- Stale bundle reconciliation is implemented for bundle-managed cleanup.
- Bundle freshness hardening is implemented and smoke-verified.
- Replacement / rollback hardening is implemented and smoke-verified.
- Multi-project churn coverage is implemented at the service level.
- Remaining work is mostly broader regression breadth, gate wiring, and future protocol evolution.
