Repository navigation
feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes #1286
Description
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
- Run a Cloud Session turn in a fresh sandbox hydrated from its latest checkpoint.
- Commit the turn before publishing its reply.
- Destroy the sandbox and continue the same Cloud Session in another fresh sandbox.
- Fork a committed checkpoint into a new Cloud Session and verify source/fork divergence.
- 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
- feat(cli): split bundled session state root from injected config root #1338 / feat(cli): split portable session state from host config (#1338) #1349 — split application state/config roots from workspace content.
- fix(runtime): identify workspaces by UUID marker instead of fs dev/ino/path #1337 / fix(runtime): identify workspaces by UUID marker #1369 — establish durable Workspace UUID identity.
- chore: measure session bundle size and cold-start budget #1336 / chore: add real session bundle measurement harness (#1336) #1353 — measure workspace materialization and define policy.
- feat(storage): define and implement the Session Bundle filesystem codec #1528 — implement the Session Bundle filesystem codec.
- feat(cli): expose a one-shot Cloud Session activation protocol #1554 — define the one-shot Cloud Session activation protocol.
- feat(cloud): fork Cloud Sessions at committed revisions #1415 — fork a Cloud Session from a committed checkpoint.
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:
- Create the quiescent snapshot issue after feat(storage): define and implement the Session Bundle filesystem codec #1528 and the chore: measure session bundle size and cold-start budget #1336 materialization decision.
- Create
SessionRepositoryafter chore: measure session bundle size and cold-start budget #1336 defines the storage class and feat(storage): define and implement the Session Bundle filesystem codec #1528 defines artifact/digest semantics.
Phase 3 — execution integration
- Create the OpenSandbox runtime/image issue after chore: measure session bundle size and cold-start budget #1336, feat(storage): define and implement the Session Bundle filesystem codec #1528, and feat(cli): expose a one-shot Cloud Session activation protocol #1554.
- Create the Activation coordinator after
SessionRepositoryand feat(cli): expose a one-shot Cloud Session activation protocol #1554. It can use a fakeActivationRuntime, so it does not need to stack on OpenSandbox.
Phase 4 — product closure
- Start feat(cloud): fork Cloud Sessions at committed revisions #1415 after quiescent snapshot, feat(storage): define and implement the Session Bundle filesystem codec #1528, and
SessionRepositoryare ready. - Create the fresh-sandbox system E2E after the coordinator, OpenSandbox runtime, and feat(cloud): fork Cloud Sessions at committed revisions #1415 are ready.
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
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
likun666661 commentedon Jul 21, 2026
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:
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
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:
The bundle materializes at a fixed path:
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 -> manifestpluscontentHash -> blob. There is no need to design file-level storage up front.The KV contract needs at least:
The control plane serializes activations for a Session.
expectedRevisionprevents a stale writer from overwriting newer state, whileactivationIddeduplicates 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:
Input:
Terminal output:
park,verify, and continuation may remain Maka-internal recovery mechanisms. The cloud control plane consumes only the stableActivationOutcome. T1/T2, cwd fingerprints, and RecoveryPlanner taxonomy therefore do not become part of the cloud platform protocol.4. Activation commit sequence
activationIdin the control plane.revisionand bundle for thesessionIdfrom KV./session./session.expectedRevision.The OpenSandbox
sandboxIdmay change on every activation. Cross-activation stable identities are only: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:
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:
The actual Maka-side work is:
sessionRoot/stateRootinstead of relying on Desktop/CLI global application storage.activationIdand terminal outcome so duplicate requests return the existing result.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”,而是:
这里的稳定资源是
sessionId,不是 sandbox、进程、cwd 或 volume。OpenSandbox sandbox 可以在每次消息到达时重新创建,执行结束后立即销毁。1. 顶层架构
OpenSandbox 负责 sandbox lifecycle、隔离、网络、凭据注入、命令执行和流式输出。Maka Cloud 控制面负责 Agent/Session 身份、消息队列、activation 幂等和结果路由。Maka harness 不需要感知 placement 或存储后端。
2. 持久化模型
MVP 可以直接把一个 Session 的完整可变状态保存为 KV value:
Bundle 解压后是一个固定目录:
不包含全局凭据、宿主机配置、缓存、依赖目录或整个 container rootfs。模型配置、权限和 secrets 由控制面在每次 activation 时注入。
整个 bundle 作为单值提交,MVP 获得天然的 Session 级原子性。等实际遇到 value 大小或传输瓶颈,再演进为
sessionId -> manifest、contentHash -> blob,不需要现在提前设计文件级存储。KV 至少需要:
控制面保证同一个 Session 的 activation 串行;
expectedRevision用于防止 stale writer 覆盖新状态;activationId用于消息重投时去重。CAS 保护的是状态提交,不能替代执行侧的串行化。3. Maka 对外只需要一个 Activation Contract
建议增加一个 cloud/headless runner,而不是暴露 RecoveryPlanner 内部概念:
输入:
终态输出:
park / verify / continuation可以继续作为 Maka 内部恢复机制,但云控制面只消费稳定的 ActivationOutcome。这样不会把 T1/T2、cwd fingerprint、RecoveryPlanner taxonomy 变成云平台协议。4. 一次 activation 的提交顺序
activationId。sessionId当前 revision 和 bundle。/session。/session。expectedRevisionCAS 写入新 bundle。OpenSandbox 的
sandboxId每轮都可以变化。跨轮稳定身份只有:5. MVP 可靠性边界需要显式写清楚
如果 bundle 只在 turn 结束时提交,那么 sandbox 在 turn 中途永久丢失时,会退回上一版 bundle。重试该 activation 可能重复尚未来得及外置的副作用。
因此建议 MVP 明确采用:
Maka 现有 T1/T2 能改善同一份 durable ledger 上的 crash recovery,但如果 ledger 仍只存在于即将丢失的 sandbox 内,它并不能自动提供跨 sandbox 的 mid-turn durability。若产品确实要求这一点,后续再增加 write-through remote journal 或增量 checkpoint;这应是独立阶段,而不是 MVP 的隐含前提。
6. 对当前 RFC 工作项的影响
在这个架构下,Maka MVP 不需要:
Maka 侧真正需要的工作项是:
sessionRoot/stateRoot,不依赖 Desktop/CLI 的全局应用目录;activationId和 terminal outcome,支持重复请求返回既有结果;我建议把 RFC 的题目和主线改成 “Portable Maka Sessions on Ephemeral OpenSandbox”。云端弹性的核心不是恢复旧进程,而是让一个 Session 能在任意新 sandbox 中被可靠地 materialize、执行一轮并重新提交。
likun666661 commentedon Jul 21, 2026
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:
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:
OpenSandbox should remain an implementation detail of the cloud control plane rather than becoming a dependency of Maka core.
A small boundary is sufficient:
The first implementation can be
KvSessionRepositoryplusOpenSandboxActivationRuntime. This keeps both the storage backend and sandbox provider replaceable.Why OpenSandbox already fits
The most relevant OpenSandbox examples are:
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:
The Maka Cloud control plane can therefore stay in TypeScript.
Session bundle
Use a binary KV key:
The value can initially be one compressed
tar.zstbundle: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,
SessionRepositorycan move large blobs behind an object store without changing the activation model.Activation lifecycle
For each request:
bundle + revisionfrom KV.finally.Fixed in-sandbox paths matter because current Maka session headers persist the state root and working directory.
Maka-side change
The existing
maka runalready supports one-shot execution,--resume,--cwd, timeouts, step limits, and non-interactive permission modes. However, it is not yet a clean cloud protocol:@maka/headlessis evaluation-oriented and isolates tools outside the runtime; it is not the right topology when the entire Maka runtime runs inside OpenSandboxI suggest adding a thin operational entry point:
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 launchmaka activatethrough 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:
activationIdreturns the committed result instead of invoking the model againIf 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:
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
maka run: hydrate a bundle, execute one turn, save it, destroy the sandbox, and resume it in a second sandbox.maka activatewith explicit state/workspace roots and structured output.activationIdand verify it does not execute twice.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 方案可以大幅简化:
这个方案不需要 PVC、常驻 Agent 进程、rootfs snapshot,也不需要 OpenSandbox pause/resume。
三个核心抽象
RFC 最主要应该描述三个概念:
OpenSandbox 应当只是云端控制面的实现细节,而不应该成为 Maka core 的依赖。
只需要一个很小的边界:
第一版实现可以是
KvSessionRepository加OpenSandboxActivationRuntime。这样存储后端和 sandbox provider 都可以独立替换。为什么 OpenSandbox 已经足够
最相关的 OpenSandbox 示例是:
OpenClaw 示例使用常驻 gateway,因此不是我们需要的拓扑。
OpenSandbox JavaScript SDK 已经提供:
因此 Maka Cloud 控制面可以继续使用 TypeScript。
Session bundle
使用二进制 KV key:
value 第一版可以是一个压缩的
tar.zst: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 生命周期
每个请求执行:
bundle + revision。finally中销毁 sandbox。固定的 sandbox 内路径很重要,因为当前 Maka session header 会持久化 state root 和 working directory。
Maka 侧需要的改动
现有
maka run已经支持单轮执行、--resume、--cwd、timeout、step limit 和非交互 permission mode。但它还不是一个干净的云端协议:@maka/headless面向评测,并且是 runtime 在外、tool 在隔离环境中的模式;整个 Maka runtime 运行在 OpenSandbox 内时不适合直接复用建议增加一个很薄的 operational 入口:
输出示例:
{"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 可以保持较小的语义范围:
activationId返回已经提交的结果,不再次调用模型如果以后加入 token streaming,则 delta 在最终 committed event 之前都应视为 provisional。
明确不需要的内容
这个架构不需要以下 OpenSandbox 能力:
OpenSandbox 只负责临时计算、文件传输、命令执行、网络策略和凭证注入。外部 KV 中的 session bundle 才是持久化 source of truth。
建议验证顺序
maka run做 smoke test:恢复 bundle、执行一轮、保存 bundle、销毁 sandbox,然后在第二个 sandbox 中继续。maka activate。activationId,确认不会执行两次。这样可以得到一个边界很窄的 MVP,同时保留以后加入 streaming、大文件存储和更复杂恢复机制的路径。
Astro-Han commentedon Jul 21, 2026
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
sessionId/revision/activationIdas the only stable identities — this is the right identity modelmaka activateas the single door between control plane and harness, RecoveryPlanner internals staying internal — this boundary is exactly rightWhat 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:
createFileCredentialStore(workspaceRoot)andcreateConnectionStore(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.SessionRepositoryfrom v1 — the implementation can wait, the seam can't.blockeda 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 versionedrequiredActionschema 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 thependingCwdReminderworkaround 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
maka activate: extendmaka runor a new entry — per our "extend the nearest seam" convention this deserves a sentence of justification either wayThanks 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.
[-][RFC] Making Maka Elastically Orchestratable: What an External Cloud Runtime Needs from the Harness[/-][+][RFC] Portable Maka Sessions on Ephemeral OpenSandbox[/+]Nyvo-io commentedon Jul 22, 2026
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:
stateRootandconfigRootinputs at the nearest shared bootstrap seam, while preserving the current local CLI/Desktop paths as backward-compatible defaults.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.
Astro-Han commentedon Jul 22, 2026
First wave of Maka-side work is now split out:
The rest (bundle import/export,
blockedcontract,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.MicroGery commentedon Jul 23, 2026
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:
The target keeps the same
agentIdby default, receives a newsessionId, and gets its own revision/CAS sequence.Proposed contract
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:
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:
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:
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:
It must not copy control-plane execution state:
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:
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, andlastActivationId. 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:
tar.zst;forkedFromlineage.It cannot safely point both Session heads at the exact same bundle value.
Validation
I would cover at least:
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.
Astro-Han commentedon Jul 23, 2026
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.
MicroGery commentedon Jul 25, 2026
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:
state/tree, produced by the state projection/export work in feat(cli): split bundled session state root from injected config root #1338 / feat(cli): split portable session state from host config (#1338) #1349;workspace/tree.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
packcreates a deterministictar.zstbundle from prepared state and workspace roots.inspectvalidates and describes a bundle without publishing it into runtime directories.hydratesafely restores a verified bundle into fresh state and workspace roots.V1 bundle contract
The bundle will contain:
The manifest will be schema-versioned and will keep a logical separation between:
The repository-assigned revision/head will not be embedded in the bundle manifest. Those remain responsibilities of
SessionRepository. Fork lineage such asforkedFrommay be carried in the envelope.Validation and safety
The implementation will include:
For V1, hydration will require fresh, empty destinations. Overwriting or merging an existing live session is out of scope.
Explicitly out of scope
SessionRepositoryimplementation;I propose implementing this in two reviewable PRs under the same issue:
tar.zstpack/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
likun666661 commentedon Jul 25, 2026
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:
sessionId,makaSessionId, activation metadata, andforkedFromare authoritative. In particular, replace “may be carried” with a V1 decision. Repository revision/head should remain outside the bundle as proposed.tar.zstdeterminism should be scoped to fixed codec/version/settings.state/andworkspace/separately can leave a half-published result after interruption. Define either a common-root atomic publication boundary or an explicit incomplete-marker/recovery protocol.inspectandhydrateshould share the same validator, whilehydratemust 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.
MicroGery commentedon Jul 27, 2026
@likun666661 Thanks — agreed on the dedicated child issue and the separate snapshot-coordinator follow-up.
I have refined the four contract points as follows:
Manifest authority
sessionIdis allocated by the control plane and is authoritative in the repository record. The bundle envelope carries it as a required binding;hydratemust reject a mismatch with the expected target session rather than silently rebinding it.makaSessionIdis a required manifest mirror of the Maka identity embedded instate/(SessionHeader.idand related state). The state payload is authoritative, and any mismatch makes the bundle invalid.makaSessionId, the fork/state layer must first produce a consistently re-keyed prepared state snapshot and then callpack.lastCommittedActivationId. It is bundle provenance only; the control-plane activation table remains authoritative for deduplication and terminal outcomes.forkedFromremains 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.Digest and canonicalization domains
state/andworkspace/;manifest.jsonis excluded to avoid self-reference.packand stored by the repository layer.0755; regular files are normalized to0644or0755, preserving only executable/non-executable semantics.tar.zstdeterminism is guaranteed only for a fixed codec version, canonicalization version, tar format, and zstd settings.Crash-safe hydration publication
I propose the common-root option for V1:
state/andworkspace/below that staging root;The resulting cloud layout would be
/session/stateand/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.Validation execution
inspectandhydratewill be two sinks over the same streaming validator:inspectvalidates the complete stream and discards payload bytes;hydratevalidates the bytes it consumes while writing only to staging;hydratenever trusts a previousinspect;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.
likun666661 commentedon Jul 27, 2026
@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:
Keep the filesystem codec independent of Maka state semantics. Making the codec read
SessionHeader.idor otherwise understand the internal layout/schema ofstate/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 semanticmakaSessionIdconsistency 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.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, andlastActivationIdin the bundle. If the new contract requires the fork/state layer to produce a consistently re-keyed prepared snapshot beforepack, 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 newmakaSessionId, which layer owns the re-key, and whether the target'slastCommittedActivationIdis 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.
MicroGery commentedon Jul 27, 2026
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.
[-][RFC] Portable Maka Sessions on Ephemeral OpenSandbox[/-][+]feat(cloud): build the Cloud Agent runtime on ephemeral sandboxes[/+]MicroGery commentedon Aug 6, 2026
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:
Quiescent snapshot coordinator
state/ + workspace/snapshot;packruns;PreparedSessionBundleSnapshotconsumed by the filesystem codec;SessionRepository
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 CloudsessionId, clearlastCommittedActivationId, and atomically create the target Session withforkedFrommetadata andforkIdidempotency.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.
likun666661 commentedon Aug 6, 2026
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:
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.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.
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.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.
MicroGery commentedon Aug 7, 2026
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 -> targetSessionIdsurvives 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.