Skip to content

feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes #1286

Open
5 of 6 issues completed
Open

Description

@Astro-Han

Outcome

Build the Cloud Agent runtime on ephemeral sandboxes while preserving durable Cloud Session continuity.

Each turn follows this lifecycle:

checkout → create fresh sandbox → hydrate → run one Activation → pack → CAS commit → publish reply → destroy sandbox

A Cloud Session is the stable resource. Sandboxes are replaceable execution environments, while a Workspace is portable durable content identified independently from local paths and sandbox IDs.

MVP acceptance

  1. Run a Cloud Session turn in a fresh sandbox hydrated from its latest checkpoint.
  2. Commit the turn before publishing its reply.
  3. Destroy the sandbox and continue the same Cloud Session in another fresh sandbox.
  4. Fork a committed checkpoint into a new Cloud Session and verify source/fork divergence.
  5. Cover the full journey with a deterministic system test.

The implementation must also reject stale commits, avoid duplicating redelivered Activations, prevent uncommitted replies from becoming visible, and exclude secrets from Session Bundles.

Core invariants

  • The Cloud Session record owns lifecycle state, generation, active lease, and committed head.
  • Workspace UUID is durable and portable; workspace paths and sandbox IDs are runtime-local.
  • Session Bundles are immutable, versioned artifacts with deterministic inclusion rules.
  • One Activation owns one turn and one lease epoch.
  • Pack, upload, and compare-and-swap commit complete before the reply becomes visible.
  • Sandbox-provider behavior stays behind the Activation runtime boundary.

Current sub-issues

Progress: 2 of 6 completed.

Delivery process

Phase 0 — completed foundations

#1338/#1349 and #1337/#1369 established the state boundary and portable Workspace identity.

Phase 1 — flat work now

#1336/#1353, #1528, and #1554 can proceed independently from the latest main.

Phase 2 — persistence contracts

After the Phase 1 contracts are settled:

Phase 3 — execution integration

Phase 4 — product closure

Delivery dependency graph

flowchart TD
  F["Completed foundations<br/>#1338/#1349 · #1337/#1369"] --> M["Measurements and policy<br/>#1336/#1353"]
  F --> B["Bundle codec<br/>#1528"]
  F --> A["Activation protocol<br/>#1554"]

  M --> S["Quiescent snapshot<br/>pending issue"]
  B --> S

  M --> R["SessionRepository<br/>pending issue"]
  B --> R

  M --> O["OpenSandbox runtime + image<br/>pending issue"]
  B --> O
  A --> O

  R --> C["Activation coordinator<br/>pending issue"]
  A --> C

  S --> K["Cloud Session fork<br/>#1415"]
  B --> K
  R --> K

  C --> E["Fresh-sandbox system E2E<br/>pending issue"]
  O --> E
  K --> E
Loading

Working rules

  • Dependency arrows are merge gates, not instructions to stack branches.
  • Start independently buildable and reviewable work from the latest main.
  • Do not create dependent issues until their required contracts merge.
  • Re-evaluate downstream scope after upstream work lands.
  • Do not combine multiple graph nodes in one PR unless they are technically inseparable.

Out of scope

  • Persistent per-session sandboxes or PVCs.
  • Mid-turn crash recovery and exactly-once external side effects.
  • Arbitrary historical forks, copy-on-write optimization, and artifact garbage collection.
  • Full approval-resume workflows.
  • Multiple sandbox providers and warm pools.

Activity

  1. likun666661 commented on Jul 21, 2026

    @likun666661
    Member

    Proposal: Portable Session Bundles on Ephemeral OpenSandbox

    I suggest reframing this RFC one abstraction level higher. The target architecture should not require Maka itself to understand cloud scheduling, volumes, or fencing. Instead:

    OpenSandbox provides ephemeral compute; an external KV store persists a portable Maka Session; Maka executes one activation at a time.

    The stable resource is the sessionId, not a sandbox, process, cwd, or volume. An OpenSandbox instance may be created for each incoming message or scheduled trigger and destroyed immediately after execution.

    1. Top-level architecture

    message / schedule
            |
            v
    Maka Cloud Control Plane
      - activation dedupe
      - per-session serialization
      - KV load / CAS commit
            |
            v
    OpenSandbox.create()
            |
            v
    hydrate Session Bundle
            |
            v
    maka activate (one turn)
            |
            v
    export Session Bundle
            |
            v
    KV CAS commit -> deliver reply -> destroy sandbox
    

    OpenSandbox owns sandbox lifecycle, isolation, networking, credential injection, command execution, and streaming output. The Maka Cloud control plane owns Agent/Session identity, the stimulus queue, activation idempotency, and result routing. The Maka harness does not need to know about placement or the persistence backend.

    2. Persistence model

    For the MVP, a Session's complete mutable state can be stored directly as one KV value:

    key: maka/session/{sessionId}
    
    value:
      revision
      lastActivationId
      bundle: tar.zst
    

    The bundle materializes at a fixed path:

    /session/
      maka-state/   # Session-owned header/messages/runs/RuntimeEvents/tool state
      files/        # Files visible to and produced by this Session
    

    It should not contain global credentials, host configuration, caches, dependency directories, or the container rootfs. Model configuration, permissions, and secrets are injected by the control plane for each activation.

    Storing the whole bundle as one value gives the MVP Session-level atomic commits. If value size or transfer cost later becomes a real bottleneck, this can evolve into sessionId -> manifest plus contentHash -> blob. There is no need to design file-level storage up front.

    The KV contract needs at least:

    load(sessionId): {
      revision: number
      lastActivationId?: string
      bundle: Uint8Array
    }
    
    commit(sessionId, {
      expectedRevision: number
      activationId: string
      bundle: Uint8Array
    }): {
      revision: number
    }

    The control plane serializes activations for a Session. expectedRevision prevents a stale writer from overwriting newer state, while activationId deduplicates message redelivery. CAS protects state publication; it does not replace execution-side serialization.

    3. Maka only needs an Activation Contract

    Rather than exposing RecoveryPlanner internals, add a small cloud/headless runner:

    maka activate \
      --session-root /session \
      --activation-id <id> \
      --input /tmp/activation.json \
      --output jsonl

    Input:

    type ActivationRequest = {
      activationId: string
      sessionId: string
      stimulus: {
        type: 'message' | 'schedule' | 'system'
        payload: unknown
      }
    }

    Terminal output:

    type ActivationOutcome =
      | { status: 'completed'; response: unknown }
      | { status: 'blocked'; reason: string; requiredAction?: unknown }
      | { status: 'retryable_failure'; reason: string }
      | { status: 'fatal_failure'; reason: string }

    park, verify, and continuation may remain Maka-internal recovery mechanisms. The cloud control plane consumes only the stable ActivationOutcome. T1/T2, cwd fingerprints, and RecoveryPlanner taxonomy therefore do not become part of the cloud platform protocol.

    4. Activation commit sequence

    1. Persist and claim the activationId in the control plane.
    2. Load the current revision and bundle for the sessionId from KV.
    3. Create a fresh OpenSandbox and unpack the bundle at /session.
    4. Run one Maka activation and collect JSONL events plus its terminal outcome.
    5. Repack /session.
    6. CAS the new bundle using expectedRevision.
    7. Acknowledge the stimulus and publish the final reply only after the bundle commit succeeds.
    8. Destroy the sandbox.

    The OpenSandbox sandboxId may change on every activation. Cross-activation stable identities are only:

    agentId / sessionId / revision / activationId
    

    5. Make the MVP reliability boundary explicit

    If the bundle is committed only after a turn finishes, permanent sandbox loss during that turn falls back to the previous bundle. Retrying the activation may repeat a side effect that was executed but not externalized.

    I recommend stating the MVP guarantee explicitly:

    Turn-boundary checkpointing: atomically save after a completed turn; do not promise mid-turn exactly-once recovery after infrastructure loss.

    Maka's T1/T2 protocol improves crash recovery when the durable ledger survives. If the ledger exists only inside a sandbox that is permanently lost, it does not by itself provide cross-sandbox mid-turn durability. If the product eventually requires that guarantee, add a write-through remote journal or incremental checkpointing as a separate phase rather than making it an implicit MVP dependency.

    6. Impact on the current RFC work items

    Under this architecture, the Maka MVP does not require:

    • block volumes or PVCs;
    • block-storage fencing;
    • a stable sandbox identity;
    • rootfs snapshots or hot resume;
    • a path-independent workspace UUID;
    • connecting the scheduler directly to RecoveryPlanner.

    The actual Maka-side work is:

    1. Support an explicit, isolated sessionRoot/stateRoot instead of relying on Desktop/CLI global application storage.
    2. Ensure all mutable state for one Session converges under that root.
    3. Provide Session Bundle import/export.
    4. Provide a machine-readable activation JSONL contract.
    5. Persist activationId and terminal outcome so duplicate requests return the existing result.
    6. Add a fresh-sandbox E2E test: load bundle → activate → commit → restore in another sandbox → continue.

    I suggest retitling and restructuring the RFC around “Portable Maka Sessions on Ephemeral OpenSandbox.” Cloud elasticity here is not about resurrecting an old process; it is about reliably materializing a Session in any fresh sandbox, executing one activation, and committing the updated Session again.

    中文版本

    建议重构:以 Session Bundle + Ephemeral OpenSandbox Activation 为核心

    我建议这个 RFC 换一层抽象。目标架构不是“让 Maka 自己理解云调度、volume 和 fencing”,而是:

    OpenSandbox 提供临时计算环境;外部 KV 保存可移植的 Maka Session;Maka 每次只执行一次 activation。

    这里的稳定资源是 sessionId,不是 sandbox、进程、cwd 或 volume。OpenSandbox sandbox 可以在每次消息到达时重新创建,执行结束后立即销毁。

    1. 顶层架构

    message / schedule
            |
            v
    Maka Cloud Control Plane
      - activation dedupe
      - per-session serialization
      - KV load / CAS commit
            |
            v
    OpenSandbox.create()
            |
            v
    hydrate Session Bundle
            |
            v
    maka activate (one turn)
            |
            v
    export Session Bundle
            |
            v
    KV CAS commit -> deliver reply -> destroy sandbox
    

    OpenSandbox 负责 sandbox lifecycle、隔离、网络、凭据注入、命令执行和流式输出。Maka Cloud 控制面负责 Agent/Session 身份、消息队列、activation 幂等和结果路由。Maka harness 不需要感知 placement 或存储后端。

    2. 持久化模型

    MVP 可以直接把一个 Session 的完整可变状态保存为 KV value:

    key: maka/session/{sessionId}
    
    value:
      revision
      lastActivationId
      bundle: tar.zst
    

    Bundle 解压后是一个固定目录:

    /session/
      maka-state/   # 该 Session 独占的 header/messages/runs/RuntimeEvents/tool state
      files/        # 该 Session 可见和产生的文件
    

    不包含全局凭据、宿主机配置、缓存、依赖目录或整个 container rootfs。模型配置、权限和 secrets 由控制面在每次 activation 时注入。

    整个 bundle 作为单值提交,MVP 获得天然的 Session 级原子性。等实际遇到 value 大小或传输瓶颈,再演进为 sessionId -> manifest、contentHash -> blob,不需要现在提前设计文件级存储。

    KV 至少需要:

    load(sessionId): {
      revision: number
      lastActivationId?: string
      bundle: Uint8Array
    }
    
    commit(sessionId, {
      expectedRevision: number
      activationId: string
      bundle: Uint8Array
    }): {
      revision: number
    }

    控制面保证同一个 Session 的 activation 串行;expectedRevision 用于防止 stale writer 覆盖新状态;activationId 用于消息重投时去重。CAS 保护的是状态提交,不能替代执行侧的串行化。

    3. Maka 对外只需要一个 Activation Contract

    建议增加一个 cloud/headless runner,而不是暴露 RecoveryPlanner 内部概念:

    maka activate \
      --session-root /session \
      --activation-id <id> \
      --input /tmp/activation.json \
      --output jsonl

    输入:

    type ActivationRequest = {
      activationId: string
      sessionId: string
      stimulus: {
        type: 'message' | 'schedule' | 'system'
        payload: unknown
      }
    }

    终态输出:

    type ActivationOutcome =
      | { status: 'completed'; response: unknown }
      | { status: 'blocked'; reason: string; requiredAction?: unknown }
      | { status: 'retryable_failure'; reason: string }
      | { status: 'fatal_failure'; reason: string }

    park / verify / continuation 可以继续作为 Maka 内部恢复机制,但云控制面只消费稳定的 ActivationOutcome。这样不会把 T1/T2、cwd fingerprint、RecoveryPlanner taxonomy 变成云平台协议。

    4. 一次 activation 的提交顺序

    1. 控制面持久化并认领 activationId。
    2. 从 KV 读取 sessionId 当前 revision 和 bundle。
    3. 创建全新 OpenSandbox,解包到固定路径 /session。
    4. 运行一轮 Maka activation,收集 JSONL events 和 terminal outcome。
    5. 重新打包 /session。
    6. 用 expectedRevision CAS 写入新 bundle。
    7. 只有 bundle commit 成功后才确认消息并向用户发布最终回复。
    8. 销毁 sandbox。

    OpenSandbox 的 sandboxId 每轮都可以变化。跨轮稳定身份只有:

    agentId / sessionId / revision / activationId
    

    5. MVP 可靠性边界需要显式写清楚

    如果 bundle 只在 turn 结束时提交,那么 sandbox 在 turn 中途永久丢失时,会退回上一版 bundle。重试该 activation 可能重复尚未来得及外置的副作用。

    因此建议 MVP 明确采用:

    turn-boundary checkpoint:完成一轮后原子保存;不承诺基础设施丢失后的 mid-turn exactly-once recovery。

    Maka 现有 T1/T2 能改善同一份 durable ledger 上的 crash recovery,但如果 ledger 仍只存在于即将丢失的 sandbox 内,它并不能自动提供跨 sandbox 的 mid-turn durability。若产品确实要求这一点,后续再增加 write-through remote journal 或增量 checkpoint;这应是独立阶段,而不是 MVP 的隐含前提。

    6. 对当前 RFC 工作项的影响

    在这个架构下,Maka MVP 不需要:

    • block volume / PVC;
    • block storage fencing;
    • stable sandbox identity;
    • rootfs snapshot 或 hot resume;
    • path-independent workspace UUID;
    • 把 scheduler 接入 RecoveryPlanner。

    Maka 侧真正需要的工作项是:

    1. 支持显式、隔离的 sessionRoot/stateRoot,不依赖 Desktop/CLI 的全局应用目录;
    2. 保证单个 Session 的全部可变状态可以收敛到该 root;
    3. 提供 Session Bundle 的 import/export;
    4. 提供 machine-readable activation JSONL contract;
    5. 持久化 activationId 和 terminal outcome,支持重复请求返回既有结果;
    6. 加一条 fresh-sandbox E2E:load bundle → activate → commit → 在另一个 sandbox 恢复并继续。

    我建议把 RFC 的题目和主线改成 “Portable Maka Sessions on Ephemeral OpenSandbox”。云端弹性的核心不是恢复旧进程,而是让一个 Session 能在任意新 sandbox 中被可靠地 materialize、执行一轮并重新提交。

  2. likun666661 commented on Jul 21, 2026

    @likun666661
    Member

    Follow-up: using OpenSandbox as the execution substrate

    After checking the OpenSandbox examples and JavaScript SDK, I think the cloud-agent design can be substantially simpler:

    Persist one Maka session in an external KV store. Treat every user turn as an ephemeral activation executed in a fresh OpenSandbox sandbox. Commit the updated session and its files back to KV, then destroy the sandbox.

    This does not require PVCs, long-lived agent processes, rootfs snapshots, or OpenSandbox pause/resume.

    The three abstractions

    The RFC should primarily describe three concepts:

    1. Cloud Session — durable Maka state and files.
    2. Activation — one attempt to process one user input.
    3. Sandbox — temporary compute used by an activation.

    OpenSandbox should remain an implementation detail of the cloud control plane rather than becoming a dependency of Maka core.

    A small boundary is sufficient:

    interface SessionRepository {
      checkout(sessionId: string): Promise<{
        revision: string;
        bundle: Uint8Array | null;
      }>;
    
      commit(
        sessionId: string,
        expectedRevision: string,
        bundle: Uint8Array,
      ): Promise<boolean>;
    }
    
    interface ActivationRuntime {
      run(input: {
        sessionId: string;
        activationId: string;
        bundle: Uint8Array | null;
        message: string;
      }): Promise<{
        bundle: Uint8Array;
        finalOutput: string;
      }>;
    }

    The first implementation can be KvSessionRepository plus OpenSandboxActivationRuntime. This keeps both the storage backend and sandbox provider replaceable.

    Why OpenSandbox already fits

    The most relevant OpenSandbox examples are:

    • Codex CLI and Claude Code: run an agent CLI inside a sandbox.
    • LangGraph: an external controller creates a sandbox, writes inputs, runs work, reads results, and cleans up.
    • Agent Sandbox: the minimal lifecycle.
    • AKS + Kata: Credential Vault and network isolation.

    The OpenClaw example uses a long-running gateway and is therefore not the topology we want.

    The OpenSandbox JavaScript SDK already provides everything required here:

    • sandbox create/delete and TTL
    • binary and streaming file upload/download
    • command execution with working directory, environment, timeout, and SSE output
    • deny-by-default network policies
    • Credential Vault
    • sandbox metadata for observability

    The Maka Cloud control plane can therefore stay in TypeScript.

    Session bundle

    Use a binary KV key:

    maka/session/{sessionId}
    

    The value can initially be one compressed tar.zst bundle:

    manifest.json
    state/
      sessions/
      runtime.sqlite
      artifacts/
    workspace/
      user-provided files
      files created or modified by the agent
    

    state/ is a dedicated Maka state root for exactly one cloud session, preventing unrelated sessions from leaking into the same bundle.

    The manifest should include at least:

    {
      "schemaVersion": 1,
      "sessionId": "...",
      "makaSessionId": "...",
      "lastActivationId": "...",
      "completedActivations": [],
      "updatedAt": "..."
    }

    The bundle must not contain real provider credentials, OpenSandbox credentials, temporary activation input, or temporary logs. Model connection configuration should be injected for each activation, and real provider secrets should be supplied through OpenSandbox Credential Vault.

    For the first version, it is reasonable to set a compressed bundle-size limit. If files later outgrow the KV value limit, SessionRepository can move large blobs behind an object store without changing the activation model.

    Activation lifecycle

    For each request:

    1. Acquire a per-session lease, or reject/queue a concurrent activation.
    2. Load bundle + revision from KV.
    3. Create a fresh sandbox from a prebuilt Maka image.
    4. Configure sandbox metadata, network policy, and Credential Vault.
    5. Upload and unpack the bundle at fixed paths.
    6. Upload activation input as JSON; do not put the user message in a shell argument.
    7. Run one Maka activation.
    8. Repack the updated session state and workspace.
    9. Download the new bundle.
    10. Commit it to KV with compare-and-set against the checked-out revision.
    11. Mark the final response as committed only after CAS succeeds.
    12. Destroy the sandbox in finally.

    Fixed in-sandbox paths matter because current Maka session headers persist the state root and working directory.

    Maka-side change

    The existing maka run already supports one-shot execution, --resume, --cwd, timeouts, step limits, and non-interactive permission modes. However, it is not yet a clean cloud protocol:

    • its workspace root is inferred from HOME/XDG
    • session state, connection configuration, settings, and credentials share one root
    • it prints only final text after the runtime closes
    • creating a session does not return a structured session identity
    • @maka/headless is evaluation-oriented and isolates tools outside the runtime; it is not the right topology when the entire Maka runtime runs inside OpenSandbox

    I suggest adding a thin operational entry point:

    maka activate \
      --state-root /maka/state \
      --workspace-root /workspace \
      --input /run/activation.json \
      --output jsonl
    

    Example output:

    {"type":"activation.started","activationId":"...","sessionId":"..."}
    {"type":"assistant.delta","text":"..."}
    {"type":"activation.completed","makaSessionId":"...","finalOutput":"..."}

    This should reuse the existing Maka runtime bootstrap rather than introduce another agent runtime.

    Image and cold start

    The Codex and Claude examples install their CLIs after sandbox creation, which is fine for a demo but not for production.

    We should build a versioned Maka image containing Node.js 24, the built Maka distribution, tar, zstd, and a neutral idle entrypoint. The controller should launch maka activate through OpenSandbox execd after hydrating the bundle. Making the agent itself the container entrypoint would complicate input hydration and result collection.

    Failure and concurrency semantics

    The MVP contract can remain intentionally small:

    • only one active activation per session
    • a session lease for admission and CAS as the final authority
    • sandbox failure before commit leaves the previous KV revision untouched
    • if commit succeeds but the client disconnects, retrying the same activationId returns the committed result instead of invoking the model again
    • a CAS loser must not return an uncommitted final response
    • checkpointing occurs at turn boundaries; mid-turn process recovery is out of scope for the MVP
    • exactly-once external side effects require tool-level idempotency and cannot be provided by session CAS alone

    If live token streaming is added, deltas should be considered provisional until a final committed event is emitted.

    Explicitly out of scope

    For this architecture, the following OpenSandbox features are unnecessary:

    • PVCs or persistent volume mounts
    • long-lived per-session sandboxes
    • pause/resume
    • rootfs snapshot persistence
    • stable sandbox identity
    • OpenClaw-style gateway ingress

    OpenSandbox supplies ephemeral compute, filesystem transfer, command execution, network policy, and credential injection. The external KV-backed session bundle remains the durable source of truth.

    Suggested validation sequence

    1. Smoke test with the current maka run: hydrate a bundle, execute one turn, save it, destroy the sandbox, and resume it in a second sandbox.
    2. Add maka activate with explicit state/workspace roots and structured output.
    3. Verify session context and files survive sandbox replacement.
    4. Kill a sandbox before commit and verify the old KV revision remains valid.
    5. Retry the same activationId and verify it does not execute twice.
    6. Verify the persisted bundle never contains real credentials.

    This gives us a narrow MVP while preserving a clean path to streaming, larger file storage, and more sophisticated recovery later.

    中文版本

    补充:使用 OpenSandbox 作为执行底座

    看过 OpenSandbox 的 examples 和 JavaScript SDK 之后,我认为云端 Agent 方案可以大幅简化:

    一个 Maka session 持久化在外部 KV 中。每次用户输入都是一次 activation,在全新的 OpenSandbox sandbox 中执行。执行完成后,把更新后的 session 和文件提交回 KV,然后销毁 sandbox。

    这个方案不需要 PVC、常驻 Agent 进程、rootfs snapshot,也不需要 OpenSandbox pause/resume。

    三个核心抽象

    RFC 最主要应该描述三个概念:

    1. Cloud Session:持久化的 Maka 状态和文件。
    2. Activation:处理一次用户输入的一次执行尝试。
    3. Sandbox:Activation 使用的临时计算环境。

    OpenSandbox 应当只是云端控制面的实现细节,而不应该成为 Maka core 的依赖。

    只需要一个很小的边界:

    interface SessionRepository {
      checkout(sessionId: string): Promise<{
        revision: string;
        bundle: Uint8Array | null;
      }>;
    
      commit(
        sessionId: string,
        expectedRevision: string,
        bundle: Uint8Array,
      ): Promise<boolean>;
    }
    
    interface ActivationRuntime {
      run(input: {
        sessionId: string;
        activationId: string;
        bundle: Uint8Array | null;
        message: string;
      }): Promise<{
        bundle: Uint8Array;
        finalOutput: string;
      }>;
    }

    第一版实现可以是 KvSessionRepository 加 OpenSandboxActivationRuntime。这样存储后端和 sandbox provider 都可以独立替换。

    为什么 OpenSandbox 已经足够

    最相关的 OpenSandbox 示例是:

    OpenClaw 示例使用常驻 gateway,因此不是我们需要的拓扑。

    OpenSandbox JavaScript SDK 已经提供:

    • sandbox 创建、销毁和 TTL
    • 二进制及流式文件上传下载
    • 带工作目录、环境变量、超时和 SSE 输出的命令执行
    • 默认拒绝的网络策略
    • Credential Vault
    • 用于可观测性的 sandbox metadata

    因此 Maka Cloud 控制面可以继续使用 TypeScript。

    Session bundle

    使用二进制 KV key:

    maka/session/{sessionId}
    

    value 第一版可以是一个压缩的 tar.zst:

    manifest.json
    state/
      sessions/
      runtime.sqlite
      artifacts/
    workspace/
      用户提供的文件
      Agent 创建或修改的文件
    

    state/ 是一个只属于当前 cloud session 的 Maka state root,从而避免把无关 session 混进同一个 bundle。

    manifest 至少包含:

    {
      "schemaVersion": 1,
      "sessionId": "...",
      "makaSessionId": "...",
      "lastActivationId": "...",
      "completedActivations": [],
      "updatedAt": "..."
    }

    bundle 不得包含真实模型凭证、OpenSandbox 凭证、临时 activation 输入或临时日志。模型连接配置应在每次 activation 时注入,真实模型密钥通过 OpenSandbox Credential Vault 提供。

    第一版可以为压缩 bundle 设置大小上限。如果以后 session 文件超出 KV value 限制,可以在 SessionRepository 内部把大文件迁移到对象存储,而不改变 activation 模型。

    Activation 生命周期

    每个请求执行:

    1. 获取 session lease;并发 activation 则拒绝或排队。
    2. 从 KV 加载 bundle + revision。
    3. 用预构建 Maka 镜像创建新 sandbox。
    4. 配置 metadata、网络策略和 Credential Vault。
    5. 上传 bundle,并解压到固定路径。
    6. 把 activation 输入作为 JSON 文件上传,不把用户消息放进 shell 参数。
    7. 执行一轮 Maka activation。
    8. 重新打包更新后的 session state 和 workspace。
    9. 下载新 bundle。
    10. 使用 checkout 时的 revision 做 KV compare-and-set。
    11. 只有 CAS 成功后,才能把最终回答标记为 committed。
    12. 在 finally 中销毁 sandbox。

    固定的 sandbox 内路径很重要,因为当前 Maka session header 会持久化 state root 和 working directory。

    Maka 侧需要的改动

    现有 maka run 已经支持单轮执行、--resume、--cwd、timeout、step limit 和非交互 permission mode。但它还不是一个干净的云端协议:

    • workspace root 由 HOME/XDG 推导
    • session state、连接配置、settings 和 credentials 共用一个 root
    • runtime 关闭后才输出最终文本
    • 创建 session 时不会结构化返回 session identity
    • @maka/headless 面向评测,并且是 runtime 在外、tool 在隔离环境中的模式;整个 Maka runtime 运行在 OpenSandbox 内时不适合直接复用

    建议增加一个很薄的 operational 入口:

    maka activate \
      --state-root /maka/state \
      --workspace-root /workspace \
      --input /run/activation.json \
      --output jsonl
    

    输出示例:

    {"type":"activation.started","activationId":"...","sessionId":"..."}
    {"type":"assistant.delta","text":"..."}
    {"type":"activation.completed","makaSessionId":"...","finalOutput":"..."}

    它应当复用现有 Maka runtime bootstrap,而不是再造一套 Agent runtime。

    镜像和冷启动

    Codex 和 Claude 示例是在 sandbox 创建之后安装 CLI,适合演示,但不适合生产。

    应预构建一个版本化 Maka 镜像,包含 Node.js 24、构建后的 Maka distribution、tar、zstd 和中性的 idle entrypoint。控制面在 bundle hydrate 完成后,通过 OpenSandbox execd 启动 maka activate。如果直接把 Agent 设为容器 entrypoint,会增加输入恢复和结果收集的复杂度。

    故障和并发语义

    MVP 可以保持较小的语义范围:

    • 每个 session 同时最多一个 activation
    • session lease 负责准入,CAS 是最终提交权威
    • commit 前 sandbox 失败,不影响旧 KV revision
    • commit 成功但客户端断开时,相同 activationId 返回已经提交的结果,不再次调用模型
    • CAS 失败的一方不能返回未提交的最终回答
    • checkpoint 发生在 turn boundary;MVP 不处理 mid-turn process recovery
    • 外部系统的 exactly-once 副作用需要 tool 自己支持幂等,单靠 session CAS 无法保证

    如果以后加入 token streaming,则 delta 在最终 committed event 之前都应视为 provisional。

    明确不需要的内容

    这个架构不需要以下 OpenSandbox 能力:

    • PVC 或持久卷挂载
    • 每个 session 对应一个常驻 sandbox
    • pause/resume
    • rootfs snapshot 持久化
    • 稳定的 sandbox identity
    • OpenClaw 风格的 gateway ingress

    OpenSandbox 只负责临时计算、文件传输、命令执行、网络策略和凭证注入。外部 KV 中的 session bundle 才是持久化 source of truth。

    建议验证顺序

    1. 用当前 maka run 做 smoke test:恢复 bundle、执行一轮、保存 bundle、销毁 sandbox,然后在第二个 sandbox 中继续。
    2. 增加带显式 state/workspace root 和结构化输出的 maka activate。
    3. 验证替换 sandbox 后 session 上下文和文件仍然存在。
    4. 在 commit 前杀掉 sandbox,确认旧 KV revision 仍然有效。
    5. 重试同一个 activationId,确认不会执行两次。
    6. 验证持久化 bundle 中永远没有真实凭证。

    这样可以得到一个边界很窄的 MVP,同时保留以后加入 streaming、大文件存储和更复杂恢复机制的路径。

  3. Astro-Han commented on Jul 21, 2026

    @Astro-Han
    ContributorAuthor

    Taking the reframe — it's better than what we had, and here's what it lets us see

    This proposal does something the original RFC didn't: instead of solving fencing, volumes, and sandbox identity, it makes them disappear. That's the better engineering move, and honestly the level of abstraction we should have started from — a Session that can materialize anywhere is a cleaner idea than a harness that tolerates being moved. I'm adopting Portable Maka Sessions on Ephemeral OpenSandbox as the new spine of this RFC, and I'll restructure and retitle it.

    What lands immediately

    • The three abstractions (Cloud Session / Activation / Sandbox) with sessionId/revision/activationId as the only stable identities — this is the right identity model
    • KV + per-session serialization + CAS + activationId as the complete concurrency story
    • maka activate as the single door between control plane and harness, RecoveryPlanner internals staying internal — this boundary is exactly right
    • Turn-boundary checkpointing as the explicit MVP reliability boundary

    What the new architecture lets us see more clearly

    Working through the implications against the codebase, a few details surfaced that the reframe doesn't cover yet — none of them challenge the direction; they're the next layer down, and I'd love your take on them:

    1. State/credential root split. Today createFileCredentialStore(workspaceRoot) and createConnectionStore(workspaceRoot) put plaintext credentials in the same root as session state (packages/cli/src/runtime-bootstrap.ts). So "bundle the session root" needs a companion "never-bundle list" (credentials, connections, device id, storage-root marker, logs) — and a split between the bundled stateRoot and an injected config root. This is probably the first concrete Maka-side task.
    2. The bundle data plane. For coding sessions the node_modules question arrives on day one: bundling them means GB-scale transfers per turn, excluding them means reinstall per activation. I'd suggest we measure a real coding session's bundle size before picking, name the KV explicitly (S3-with-CAS class rather than etcd-class), and keep the manifest/blob offload seam in SessionRepository from v1 — the implementation can wait, the seam can't.
    3. Lease semantics for long turns. A 30-minute turn can outlive a session lease, and then CAS protects the state but not the external side effects that already ran. The ephemeral model actually has an elegant answer here — "destroy the old sandbox before starting a replacement activation" is fencing for free — plus lease renewal (or a time budget above p99 turn duration), a control-plane activation state machine with a reaper for orphaned sandboxes, and the activationId→outcome dedupe table living in the control plane's own store.
    4. Giving blocked a real shape. I suspect the most common blocked case in practice will be tool-permission approval: a turn suspends with a pending approval persisted in the bundle and resumes on an approval-class stimulus later. A small stable enum plus a versioned requiredAction schema would make that routable without leaking RecoveryPlanner internals. (Provisional streaming deltas deserve the same treatment.)

    One delisted item earns its way back — and it's good news

    I'd keep "path-independent workspace identity" on the list, but with a twist: it's not a new requirement, it's an existing piece of desktop tech debt that this architecture gives us a reason to finally fix properly. Today workspace identity anchors to fs:{dev}:{ino}:{resolvedPath} (packages/runtime/src/continuation-safety.ts), and resume parks on mismatch (packages/runtime/src/runtime-resume.ts) — so in a fresh sandbox, where dev/ino always change, the crash-retry path would park every time. The fix we already wanted for /move (an intrinsic UUID marker, path demoted to diagnostics) travels intact inside a tar bundle — so one change removes the pendingCwdReminder workaround on desktop and makes cross-sandbox retry work. The storage-root marker needs the same adopt-on-import treatment. This item going from "someday" to "load-bearing" is, I'd argue, a point in favor of the reframe, not against it.

    One clarification worth writing down

    "Fresh sandbox per message" reads best as a portability invariant we test, not a required production topology — sandbox reuse or warm pools don't violate the model as long as the bundle stays the source of truth. Stating that explicitly now saves a stance fight later.

    Before implementation, let's measure

    • Bundle p50/p99 size on a real coding session; per-message cold-start budget for interactive chat
    • node_modules/.git policy: reinstall, bundle, or bake into the image
    • maka activate: extend maka run or a new entry — per our "extend the nearest seam" convention this deserves a sentence of justification either way

    Thanks for pushing this up a level — it's a better frame, and it made the remaining work smaller and clearer. I'll restructure the RFC body around it and split the Maka-side items into concrete issues. Items 2 and 3 especially deserve your eyes.

  4. changed the title [-][RFC] Making Maka Elastically Orchestratable: What an External Cloud Runtime Needs from the Harness[/-] [+][RFC] Portable Maka Sessions on Ephemeral OpenSandbox[/+] on Jul 21, 2026
  5. Nyvo-io commented on Jul 22, 2026

    @Nyvo-io
    Contributor

    I would like to take the first concrete Maka-side slice from #1286: separating portable session state from injected configuration and credentials, together with an explicit bundle export policy.

    I audited the current direction before proposing the boundary. The CLI runtime bootstrap still derives session state, credentials, connections, settings, and identity files from the same host-owned root. Exporting that root as a Session Bundle would therefore risk including credentials or unrelated host state.

    My proposed first slice is:

    1. Inventory every store rooted by the current CLI/runtime bootstrap and classify it as session-owned state or injected host configuration.
    2. Introduce explicit stateRoot and configRoot inputs at the nearest shared bootstrap seam, while preserving the current local CLI/Desktop paths as backward-compatible defaults.
    3. Define one auditable export policy that includes only session-owned state and explicitly excludes credentials, connection configuration, device identity, storage-root markers, temporary activation input, and logs.
    4. Make export fail closed on symlinks, path escape, unknown protected entries, or roots that overlap unsafely.
    5. Add focused tests for legacy compatibility, root isolation, cross-session leakage, symlink/path traversal, and credential canaries proving exported material contains no secrets.

    I would keep the OpenSandbox control plane, KV/CAS implementation, bundle compression/size policy, maka activate, and activation deduplication outside this first PR. Those can build on the root/export contract once the trust boundary is stable.

    This looks like the load-bearing prerequisite for Session Bundle import/export. If you are splitting the RFC into child issues, please assign or link this slice to me. I will wait for scope confirmation and assignment before opening a branch.

  6. Astro-Han commented on Jul 22, 2026

    @Astro-Han
    ContributorAuthor

    First wave of Maka-side work is now split out:

    The rest (bundle import/export, blocked contract, maka activate, activationId dedupe, image, control plane, E2E) stays tracked here until prerequisites land. The spike results will reshape several of them, so no issues yet.

  7. MicroGery commented on Jul 23, 2026

    @MicroGery
    Contributor

    Proposal: fork Cloud Sessions at committed revisions

    I would like to take a follow-up slice for Cloud Session forking.

    I think this should be defined as a Cloud Session fork, rather than a sandbox fork or an Agent-definition fork:

    Create a new Cloud Session from the complete bundle of one committed source revision. The source and target then evolve independently.

    The target keeps the same agentId by default, receives a new sessionId, and gets its own revision/CAS sequence.

    Proposed contract

    type SessionRevisionRef = {
      sessionId: string;
      revision: string;
    };
    
    type ForkSessionRequest = {
      forkId: string;
      source: SessionRevisionRef;
      targetSessionId: string;
    };
    
    type ForkSessionResult = {
      target: SessionRevisionRef;
      forkedFrom: SessionRevisionRef;
    };

    source.revision should be required rather than implicitly meaning "latest". This prevents a race where the source advances between the user's decision to fork and the control-plane operation.

    With the current SessionRepository shape, only the current committed revision is addressable. Therefore I suggest the following MVP boundary:

    • fork only an explicitly named current committed revision;
    • return source_revision_not_available if the head has moved;
    • add arbitrary historical-revision forks only after revision retention exists;
    • never silently fork a newer revision.

    Identity and lineage

    The target's first revision must be a new revision in the target Session. It must not reuse the source revision as its own CAS token.

    Fork lineage should be stored in control-plane Session metadata:

    type CloudSessionForkLineage = {
      forkedFrom: {
        sessionId: string;
        revision: string;
      };
    };

    A revision is only unique within its Session, so lineage should use the complete (sessionId, revision) pair.

    This lineage is separate from Maka's existing parentSessionId / branchOfTurnId conversation semantics. branchFromTurn creates a conversation branch at a turn boundary; a Cloud Session fork copies the complete committed snapshot, including runtime state, artifacts, and workspace files. I would not overload the existing Maka lineage fields with cross-bundle Cloud Session lineage.

    CAS and idempotency

    A fork does not need to acquire the source Session's write lease:

    1. Read the exact committed source revision.
    2. Verify that it is forkable.
    3. Create the target Session with create-if-absent semantics.
    4. Persist forkId -> targetSessionId so retrying the request returns the same target.
    5. Let subsequent source and target activations use independent leases and CAS heads.

    The source is never modified. A race with a source commit either reads the requested revision consistently or fails with source_revision_not_available.

    What is and is not copied

    The fork copies the portable Session Bundle:

    • conversation and runtime history;
    • durable Maka state;
    • artifacts;
    • workspace files.

    It must not copy control-plane execution state:

    • active leases or sandbox identity;
    • queued/running activation records;
    • activation dedupe entries;
    • scheduler registrations;
    • injected credentials or connection configuration;
    • temporary activation input or logs.

    Activation dedupe must remain scoped by (sessionId, activationId), otherwise copied activation history could suppress a valid activation in the target Session.

    For v1 I would define a forkable source as a committed, quiescent revision. Revisions containing a pending approval or another externally resumable action should be rejected until we define how those action identities are re-keyed for the target Session.

    Storage implementation

    The semantic contract should not depend on whether bundles are physically copied:

    • the initial single-tar.zst repository may copy the bundle;
    • a later manifest/blob repository may point both Session heads at the same immutable bundleRef and use copy-on-write;
    • shared blobs then require reachability/refcount-aware garbage collection.

    This preserves the API when historical revision retention or content-addressed storage is added later.

    One constraint is that the current proposed bundle manifest contains sessionId, makaSessionId, and lastActivationId. Two Session heads may share immutable payload blobs only if target-specific identity and activation metadata lives in a separate envelope or manifest.

    Otherwise, v1 must:

    • copy the tar.zst;
    • rewrite the target-scoped manifest fields;
    • reset activation deduplication state;
    • record the forkedFrom lineage.

    It cannot safely point both Session heads at the exact same bundle value.

    Validation

    I would cover at least:

    1. source and target diverge after the fork;
    2. a source-head race never forks an unintended revision;
    3. retrying the same forkId creates only 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. shared bundle data is not collected while either Session still references it.

    This slice depends on the state/config split and the Session Bundle import/export contract, but it should not depend on OpenSandbox or maka activate: once a bundle is portable, fork is primarily a control-plane/repository operation.

    If this boundary looks right, please split it into a child issue and assign it to me.

  8. Astro-Han commented on Jul 23, 2026

    @Astro-Han
    ContributorAuthor

    Fork is now split out:

    The RFC body picked up two additions from the discussion: an envelope/payload manifest seam in the Session bundle section, and a "Cloud Session fork (planned)" section with the contract and storage direction.

  9. MicroGery commented on Jul 25, 2026

    @MicroGery
    Contributor

    I'd like to take ownership of the filesystem-facing contract and implementation for Work Item 3: Session Bundle import/export.

    My proposed scope is:

    Responsibility boundary

    The bundle layer will accept an already prepared and quiescent snapshot containing:

    It will not read directly from a live SQLite database or a workspace that is still being modified. Producing a cross-store consistent snapshot, filtering workspace contents, and coordinating runtime quiescence will remain outside this filesystem layer.

    Proposed API

    interface SessionBundleFileService {
      pack(input: SessionBundlePackInput): Promise<SessionBundleArtifact>;
      inspect(input: SessionBundleReadInput): Promise<SessionBundleInspection>;
      hydrate(input: SessionBundleHydrateInput): Promise<SessionBundleHydration>;
    }
    • pack creates a deterministic tar.zst bundle from prepared state and workspace roots.
    • inspect validates and describes a bundle without publishing it into runtime directories.
    • hydrate safely restores a verified bundle into fresh state and workspace roots.

    V1 bundle contract

    The bundle will contain:

    manifest.json
    state/
    workspace/
    

    The manifest will be schema-versioned and will keep a logical separation between:

    • an envelope, containing portable session identity and lineage metadata;
    • a payload description, containing paths, file count, expanded size, and a canonical tree digest.

    The repository-assigned revision/head will not be embedded in the bundle manifest. Those remain responsibilities of SessionRepository. Fork lineage such as forkedFrom may be carried in the envelope.

    Validation and safety

    The implementation will include:

    • schema-version validation;
    • deterministic archive generation;
    • payload tree-digest verification;
    • a full-archive digest returned to the repository layer;
    • compressed and expanded size limits;
    • file-count, per-file, manifest, path-length, and path-depth limits;
    • path traversal and absolute-path rejection;
    • duplicate and conflicting path detection;
    • rejection of symlinks, hardlinks, and special filesystem entries in V1;
    • staging-based hydration and cleanup on failure;
    • stable, bounded error codes;
    • round-trip, corrupted-bundle, quota, and malicious-archive tests.

    For V1, hydration will require fresh, empty destinations. Overwriting or merging an existing live session is out of scope.

    Explicitly out of scope

    • live SQLite snapshotting and runtime quiescence;
    • workspace filtering or secret-detection policy;
    • KV/CAS and SessionRepository implementation;
    • OpenSandbox transfer and activation orchestration;
    • fork orchestration;
    • copy-on-write, blob GC, and revision-history retention;
    • database migration after hydration.

    I propose implementing this in two reviewable PRs under the same issue:

    1. manifest/types, versioning, limits, errors, digest rules, and contract tests;
    2. deterministic tar.zst pack/inspect/hydrate implementation, safe extraction, staging, and end-to-end tests.

    If this boundary matches the maintainers' expectations for Work Item 3, please assign this issue to me. I'm happy to own the implementation and
    coordinate the contract with the state-export and repository work. @likun666661

  10. likun666661 commented on Jul 25, 2026

    @likun666661
    Member

    Thanks — this is the right filesystem-layer boundary, and the two-PR split looks reviewable.

    Let's track this as a dedicated child issue for Work Item 3 rather than assigning the umbrella RFC itself. The child issue should describe this layer explicitly as the Session Bundle filesystem codec: it consumes a prepared, quiescent snapshot and does not own cross-store snapshot coordination. We should keep a separate follow-up for the coordinator that produces one consistent state/ + workspace/ snapshot, so that responsibility does not fall through the gap between this work and #1338 / #1349.

    Before PR 1, please pin down these contract details in the child issue:

    1. Manifest authority. Decide exactly where sessionId, makaSessionId, activation metadata, and forkedFrom are authoritative. In particular, replace “may be carried” with a V1 decision. Repository revision/head should remain outside the bundle as proposed.
    2. Digest and canonicalization domains. Distinguish the canonical payload tree digest from the full-archive transport digest, and version the rules: algorithm, path encoding/order, empty directories, executable bits, and normalization of timestamps, uid/gid, and other metadata. Byte-for-byte tar.zst determinism should be scoped to fixed codec/version/settings.
    3. Crash-safe hydration publication. Staging plus fresh destinations is the right direction, but publishing state/ and workspace/ separately can leave a half-published result after interruption. Define either a common-root atomic publication boundary or an explicit incomplete-marker/recovery protocol.
    4. Validation execution. inspect and hydrate should share the same validator, while hydrate must revalidate the bytes it actually consumes rather than trusting an earlier inspection. Quotas should be enforced during streaming decompression, not only after extraction.

    With those details pinned, the proposed scope matches the intended Work Item 3 boundary. Happy for you to own the filesystem contract and implementation and coordinate it with the state-export and repository work.

  11. MicroGery commented on Jul 27, 2026

    @MicroGery
    Contributor

    @likun666661 Thanks — agreed on the dedicated child issue and the separate snapshot-coordinator follow-up.

    I have refined the four contract points as follows:

    1. Manifest authority

      • Cloud sessionId is allocated by the control plane and is authoritative in the repository record. The bundle envelope carries it as a required binding; hydrate must reject a mismatch with the expected target session rather than silently rebinding it.
      • makaSessionId is a required manifest mirror of the Maka identity embedded in state/ (SessionHeader.id and related state). The state payload is authoritative, and any mismatch makes the bundle invalid.
      • The filesystem codec will not rewrite Maka state identity. If a Cloud Session fork requires a new makaSessionId, the fork/state layer must first produce a consistently re-keyed prepared state snapshot and then call pack.
      • I propose naming the optional activation field lastCommittedActivationId. It is bundle provenance only; the control-plane activation table remains authoritative for deduplication and terminal outcomes.
      • Repository revision/head remain outside the bundle.
      • For V1, forkedFrom remains authoritative only in control-plane Session metadata, as defined by feat(cloud): fork Cloud Sessions at committed revisions #1415, and is not duplicated in the bundle manifest.
    2. Digest and canonicalization domains

      • The manifest carries a versioned SHA-256 payload tree digest over state/ and workspace/; manifest.json is excluded to avoid self-reference.
      • The final archive receives a separate SHA-256 transport digest returned by pack and stored by the repository layer.
      • V1 canonical paths are valid UTF-8, relative, slash-separated paths, ordered by raw UTF-8 bytes. No Unicode normalization or path rewriting is performed.
      • Regular files and directories, including empty directories, participate in the tree digest.
      • Directory mode is normalized to 0755; regular files are normalized to 0644 or 0755, preserving only executable/non-executable semantics.
      • Timestamps and uid/gid are normalized to zero; uname/gname are empty; xattrs, ACLs, links, and special entries are outside the V1 canonical domain.
      • Tree records use a versioned, length-prefixed encoding rather than ambiguous string concatenation.
      • Byte-for-byte tar.zst determinism is guaranteed only for a fixed codec version, canonicalization version, tar format, and zstd settings.
    3. Crash-safe hydration publication

      I propose the common-root option for V1:

      • hydrate into a sibling staging directory on the same filesystem;
      • materialize state/ and workspace/ below that staging root;
      • validate and close everything;
      • publish the complete Session root with one atomic rename;
      • require the destination root not to exist.

      The resulting cloud layout would be /session/state and /session/workspace, rather than two independently published roots. A crash before rename leaves only an orphan staging directory; after rename, the complete Session root is visible. V1 guarantees process-interruption atomicity. Host power-loss durability/fsync semantics are not required for an ephemeral sandbox because the control plane can rehydrate from the committed bundle.

    4. Validation execution

      inspect and hydrate will be two sinks over the same streaming validator:

      • inspect validates the complete stream and discards payload bytes;
      • hydrate validates the bytes it consumes while writing only to staging;
      • hydrate never trusts a previous inspect;
      • each operation opens and consumes its source independently;
      • compressed bytes, decompressed tar bytes, payload bytes, per-file bytes, entry count, manifest size, path length, and path depth are enforced while streaming;
      • tar-declared sizes are checked before writing and verified against bytes actually consumed;
      • nothing is published until identity, quota, entry, and digest validation all succeed.

    I also agree that cross-store snapshot coordination must be a separate follow-up. The codec consumes a prepared, quiescent state/ + workspace/ snapshot and does not own live SQLite coordination or workspace quiescence. #1349 has now landed the state/config split and state export side; the coordinator still needs an explicit issue so the consistency responsibility does not fall through the gap.

    I will put these decisions, the error model, acceptance criteria, and the two-PR split into the dedicated Work Item 3 child issue. Since the child issue has not been created yet, I can open it and link it here; once the scope is confirmed, please assign it to me. I will not start PR 1 until that contract is pinned.

  12. likun666661 commented on Jul 27, 2026

    @likun666661
    Member

    @MicroGery Thanks — this resolves the four points I raised, and the common-root publication plus shared streaming validator are the right direction.

    Before we treat the child-issue contract as pinned, there are two remaining boundary points to fix there:

    1. Keep the filesystem codec independent of Maka state semantics. Making the codec read SessionHeader.id or otherwise understand the internal layout/schema of state/ would violate the filesystem-layer boundary we just established. Please define a minimal, versioned identity descriptor produced and validated by the state-export layer, or leave the semantic makaSessionId consistency check to that layer. The codec may bind and integrity-check the descriptor as bytes, but should not depend on Maka's SQLite/session formats.

    2. Reconcile the changed fork contract with feat(cloud): fork Cloud Sessions at committed revisions #1415. The proposal here correctly avoids having the codec rewrite Maka identity, but feat(cloud): fork Cloud Sessions at committed revisions #1415 currently describes fork as a repository operation that rewrites sessionId, makaSessionId, and lastActivationId in the bundle. If the new contract requires the fork/state layer to produce a consistently re-keyed prepared snapshot before pack, that is a real contract change and feat(cloud): fork Cloud Sessions at committed revisions #1415 should be updated accordingly. Please also pin whether a fork always receives a new makaSessionId, which layer owns the re-key, and whether the target's lastCommittedActivationId is cleared or preserved only as provenance.

    Please include those decisions, together with the exact canonical tree-record encoding and the transport-digest verification path, in the child issue's acceptance criteria. With that done, the two-PR split looks good. Please go ahead and open the child issue and link it here; once the scope reflects these decisions, I'm happy to assign it to you.

  13. MicroGery commented on Jul 27, 2026

    @MicroGery
    Contributor

    Opened #1528 with the pinned Session Bundle filesystem-codec contract. It includes the opaque state-identity boundary, the #1415 fork-contract reconciliation, the exact canonical tree-record encoding, the transport-digest verification path, and the two-PR implementation split.

    @likun666661 Please assign it to me if the scope looks right.

  14. changed the title [-][RFC] Portable Maka Sessions on Ephemeral OpenSandbox[/-] [+]feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes[/+] on Jul 28, 2026
  15. MicroGery commented on Aug 6, 2026

    @MicroGery
    Contributor

    With #1336 / #1353 and #1528 / #1697 / #2013 now landed, the prerequisites for the two Phase 2 persistence follow-ups in the dependency graph are satisfied.

    I would like to take ownership of both remaining follow-ups:

    1. Quiescent snapshot coordinator

      • coordinate one consistent state/ + workspace/ snapshot;
      • ensure mutable stores are safe to copy and the prepared roots remain stable while pack runs;
      • produce the PreparedSessionBundleSnapshot consumed by the filesystem codec;
      • keep archive encoding, repository persistence, and Activation orchestration outside this layer.
    2. SessionRepository

      • define and implement exact committed-revision checkout;
      • persist bundle references and trusted archive digests;
      • manage Session head/revision state with CAS;
      • provide atomic create-if-absent semantics needed by a future fork target;
      • keep leases, Activation deduplication, scheduling, credentials, and sandbox lifecycle outside the repository boundary.

    I propose tracking these as two separate child issues and implementing them in independent PRs from the latest main, as required by the delivery graph.

    After both are ready, I will proceed with #1415 using the contract reconciled in #1528: the fork implementation will not rewrite a Bundle manifest or Maka state in place. It will check out the exact source revision, hydrate it privately, perform state-semantic re-keying for a new target makaSessionId, repack it for the new Cloud sessionId, clear lastCommittedActivationId, and atomically create the target Session with forkedFrom metadata and forkId idempotency.

    Please let me know whether you would prefer me to open the two child issues, or if maintainers would like to split them from #1286.

  16. likun666661 commented on Aug 6, 2026

    @likun666661
    Member

    Thanks — I verified that the measurement/policy work and the Session Bundle codec prerequisites have landed. The proposed split matches the Phase 2 dependency graph, so please go ahead and open the two child issues as independent work items from the latest main.

    Before we treat their contracts as pinned, please make the following boundaries explicit in their acceptance criteria:

    1. Prepared-snapshot lifetime. Define how the coordinator keeps the prepared roots stable through pack: either produce an immutable private staging snapshot, or return a handle whose quiescence and cleanup ownership remain active until release. Please also pin concurrent-mutation behavior, failure cleanup, and ownership of temporary roots.

    2. Filtering and secret exclusion. Assign an explicit owner for workspace filtering and secret exclusion. feat(storage): define and implement the Session Bundle filesystem codec #1528 intentionally leaves those outside the filesystem codec, while feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes #1286 still requires secrets to be excluded from Session Bundles. The responsibility should not fall between the snapshot producer and the codec.

    3. Repository publication and fork idempotency. Keep exact-revision checkout within the V1 retention boundary, define bundle/blob publication versus head-CAS ordering, and ensure the trusted archive digest is verified on checkout. Please also pin the atomicity of forkId -> targetSessionId: create-if-absent alone is not sufficient if target creation succeeds but the idempotency mapping is not durably recorded.

    4. Workspace identity during fork. Reconcile workspace identity as well as makaSessionId. fix(runtime): identify workspaces by UUID marker #1369 preserves a copied workspace UUID for ordinary import/hydration, but a fork creates independently evolving source and target workspaces. Please specify whether the target receives a new workspace UUID or intentionally preserves the source UUID, and update feat(cloud): fork Cloud Sessions at committed revisions #1415 accordingly.

    Please link both child issues here once opened. If their scopes reflect these decisions, I’m happy to assign both to you. The two-issue/two-PR split looks good.

  17. MicroGery commented on Aug 7, 2026

    @MicroGery
    Contributor

    Opened and assigned the two independent Phase 2 child issues from the latest main:

    #2369 pins the prepared-snapshot lifetime to a short live-Session quiescence interval followed by a coordinator-owned immutable private staging copy. It also assigns filtering/secret exclusion to a versioned snapshot policy enforced by the coordinator. The handling of user-authored secrets inside the Workspace is explicitly listed as a contract decision that must be resolved before implementation rather than silently defaulted.

    #2370 pins exact-current-revision checkout, immutable Bundle publication before head CAS, trusted archive-digest verification, and a durable pending/completed Fork operation record so forkId -> targetSessionId survives crashes around target creation.

    I also updated #1415 in this comment with the proposed Workspace identity boundary: a Fork target receives a new Workspace UUID, completed pre-fork history retains source provenance, and the target starts its next Activation at a new execution boundary rather than resuming source continuation state against the new Workspace.

    Both child issues are assigned to me and remain independent work items/PR series as requested.

  18. removed their assignment
    on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions