Skip to content

feat(cloud): fork Cloud Sessions at committed revisions #1415

Description

@Astro-Han

Split from @MicroGery's proposal in #1286 (#issuecomment-5059344338). Parent RFC: #1286.

Motivation

A portable bundle makes fork a control-plane/repository operation, with no dependency on OpenSandbox or maka activate. Besides user-driven duplication of a session, it enables template sessions: warm one base session (workspace set up, dependencies installed, initial context established), then fork per user/session. Every fork starts from the same conversation prefix, so provider prompt caches keep hitting, and inherits a warm workspace, so setup does not rerun per session.

Definition

Create a new Cloud Session from the complete bundle of one committed source revision; source and target then evolve independently. The target keeps the same agentId, receives a new sessionId, and starts its own revision/CAS sequence. This is a Cloud Session fork, not a sandbox fork or an agent-definition fork.

Contract

type SessionRevisionRef = { sessionId: string; revision: string };

type ForkSessionRequest = {
  forkId: string; // idempotency key
  source: SessionRevisionRef;
  targetSessionId: string;
};

type ForkSessionResult = {
  target: SessionRevisionRef;
  forkedFrom: SessionRevisionRef;
};
  • source.revision is required and never defaults to "latest". This closes the race where the source advances between the decision to fork and the operation.
  • The target's first revision is a new revision in the target session; it must not reuse the source revision as its CAS token.
  • Lineage lives in control-plane session metadata as forkedFrom: { sessionId, revision } (a revision is only unique within its session). It stays separate from Maka's conversation-level parentSessionId / branchOfTurnId: branchFromTurn branches conversation history at a turn boundary, while a Cloud Session fork copies the complete committed snapshot including runtime state, artifacts, and workspace files. Do not overload the Maka lineage fields.

MVP boundary

  • Fork only an explicitly named current committed revision; if the head has moved, fail source_revision_not_available. Never silently fork a newer revision.
  • A fork does not acquire the source session's write lease: read the exact committed revision, verify it is forkable, create the target with create-if-absent, and persist forkId -> targetSessionId so retries return the same target. The source is never modified.
  • Only quiescent revisions are forkable: reject a revision with a pending approval or another externally resumable action until action identities are re-keyed for the target session.

Copied vs not copied

Copied: conversation and runtime history, durable Maka state, artifacts, workspace files.

Never copied (control-plane execution state): active leases, sandbox identity, queued/running activation records, activation dedupe entries, scheduler registrations, injected credentials or connection configuration, temporary activation input, logs. Activation dedupe stays scoped by (sessionId, activationId) so copied history cannot suppress valid activations in the target.

Storage

  • v1: copy the tar.zst, rewrite target-scoped envelope/manifest fields (sessionId, makaSessionId, lastActivationId), reset activation dedupe state, record forkedFrom. Two session heads must not point at the exact same bundle value.
  • The semantic contract must not depend on physical copy. Once revision retention and the envelope/payload manifest seam (see feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes #1286, Session bundle section) exist, both heads may share immutable payload blobs with copy-on-write, which then requires reachability/refcount-aware GC.
  • Within-session revision history stays a linear CAS sequence in v1. Per-revision metadata (for example, which activation produced a revision) arrives with retention; v1 records lineage only at fork boundaries.

Out of scope

Arbitrary historical-revision forks (needs retention); mapping in-bundle conversation branching (/rewind, branchBeforeTurn) onto cloud sessions; copy-on-write storage and GC; re-keying pending-approval action identities.

Validation

  1. Source and target diverge after the fork.
  2. A source-head race never forks an unintended revision.
  3. Retrying the same forkId creates exactly one target.
  4. Target CAS conflicts do not affect the source.
  5. Deleting the source does not invalidate the target.
  6. Credentials, activation records, leases, and schedules are not copied.
  7. A non-quiescent or pending-approval revision is rejected.
  8. (When copy-on-write lands) shared bundle data is not collected while either session references it.

Dependencies

#1338 (state/config root split) and the Session Bundle import/export contract tracked in #1286. No dependency on OpenSandbox or maka activate.

Activity

  1. Astro-Han commented on Jul 23, 2026

    @Astro-Han
    ContributorAuthor

    @MicroGery The issue is opened.

  2. MicroGery commented on Jul 24, 2026

    @MicroGery
    Contributor

    Thanks for splitting this out. I would like to take #1415.

    I understand that the implementation depends on #1338 and the Session Bundle import/export contract. Unless you prefer otherwise, I will wait for those boundaries to settle and then implement the pinned v1 scope:

    • current committed, quiescent revisions only;
    • idempotency through forkId;
    • create-if-absent target Session;
    • physical bundle copy with target-scoped metadata rewritten;
    • the validation cases listed in this issue.

    Historical-revision forks, copy-on-write/GC, conversation-branch mapping, and pending-action re-keying will remain out of scope.

    Please assign this issue to me.

  3. MicroGery commented on Aug 7, 2026

    @MicroGery
    Contributor

    Following the Workspace-identity boundary raised in #1286, I propose updating the V1 fork contract as follows:

    • Ordinary Bundle import/hydration continues to preserve the copied Workspace UUID, as defined by fix(runtime): identify workspaces by UUID marker instead of fs dev/ino/path #1337 / fix(runtime): identify workspaces by UUID marker #1369, because it is the same logical Workspace materialized at a new path.
    • A Cloud Session fork creates an independently evolving Workspace, so the target always receives a new Workspace UUID in addition to its new Cloud sessionId, new makaSessionId, and independent revision/CAS sequence.
    • The filesystem codec does not perform this change. The fork/state-semantic layer hydrates the exact source revision into private staging, allocates the target Workspace UUID, updates the authoritative current Workspace marker/bindings consistently, and then repacks the target Bundle.
    • Completed pre-fork AgentRun/runtime records retain the source Workspace identity as historical provenance; V1 does not rewrite immutable history to pretend those runs occurred in the target Workspace.
    • Source execution-continuation state is not resumed against the new Workspace. Because V1 accepts only quiescent committed revisions and already rejects pending approvals or other externally resumable actions, the target starts its next Activation at a new AgentRun/execution boundary using the copied conversation/runtime history as context and the new target Workspace identity.
    • The state-semantic implementation must explicitly distinguish historical Workspace references from current/resumable bindings. Any current continuation/recovery cursor that would require the source Workspace identity is cleared or rejected rather than silently rebound.

    This preserves access to the complete pre-fork conversation and completed runtime history while preventing a source execution plan for Workspace W1 from being resumed against the independently evolving target Workspace W2.

    Suggested additional validation:

    1. source and target resolve different Workspace UUIDs immediately after fork;
    2. ordinary hydrate of either Session preserves that Session's UUID;
    3. pre-fork completed history remains readable and retains source provenance;
    4. the target's first post-fork Activation creates a new run under the target UUID;
    5. no pending/background/approval continuation can cross the fork boundary;
    6. source and target Workspace versioning and future mutations do not collide.

    The two newly opened Phase 2 prerequisites are #2369 (quiescent snapshot coordinator) and #2370 (SessionRepository).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions