Skip to content

Reuse finished Environment preparation across Sessions - #808

Merged
SaladDay merged 4 commits into
mainfrom
prep-cache
Oct 21, 2026
Merged

SaladDay merged 4 commits into
mainfrom
prep-cache

Conversation

@SaladDay

@SaladDay SaladDay commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

What users see

Core may start a hosted Environment from the result of an earlier preparation in the same Project whose effective configuration, after Template composition, is identical, for up to 24 hours after that preparation. Each Session still gets its own copy. Setup commands and package installation then do not run again for this Session. Only /environment is reused; HOME and other compute-local changes are not. Setup must not create per-Session unique values, perform external side effects that must happen per Session, or fetch credentials that expire within 24 hours; configurations that need this must differ (for example in env or files). Providers that do not declare the operations (Docker, E2B) always prepare in full. There is no setting, no /v1 or OpenAPI change and no management API.

Key

SHA-256 hex of: the tenant ID, then each initial file's (path, sha256 of body), then each setup operation's request (JSON) and sha256 of its data. It excludes Environment, Session, Harness and Agent. Network policy is not part of it: preparation always uses the host network and Core rejects non-enabled effective network for Sessions. Core never interprets the key beyond computing it.

Changes

  • Provider protocol: two optional operations, RestorePreparation(ref, key) (bool, error) and SavePreparation(ref, key), declared Supported or Unsupported together in each adapter's operations file. Both address the initial compute, because compute state is empty until initialization completes. Docker and E2B declare Unsupported.
  • Node wire: restore_preparation (key -> restored) and save_preparation (key), both fields added to the strict frame decoder (generation_json.go) with a round-trip test. Protocol version unchanged; the fields are additive.
  • Core worker (runtime_preparation_cache.go, runtime_initialization.go): a hit skips the file and setup operations but still sends finalize; a miss prepares and then saves; a save error is logged and does not fail the Session; a restore error fails preparation.
  • microsandbox helper (preparation.go): all storage, TTL and seeding. One tar archive of initialization, packages and workspace under /environment (never runtime-state, which holds the running daemon's Codex home, Claude SDK history and completion markers) per (key, image digest, workspace mode) in a private directory under the Runtime home, valid 24 hours, pruned past the TTL and then oldest first above 8 GiB. The bound exists because the TTL alone does not limit disk on a busy node; a measured archive is tens of MiB (51 MiB real, 200 MiB synthetic), so 8 GiB holds over a hundred. Owned disk goes through guest tar and the SDK file copy; an NFS bind goes through host tar with xattrs preserved. An entry that fails to extract is deleted, so only that Session fails. The save gets at most half of the remaining preparation budget, so it never takes the time completion needs.
  • Daemon: finalize rebinds the restored installed.json identity to the current Session when the selection hash is identical, and still rejects a different selection. One existing test that expected an identity-only mismatch to fail now uses a changed selection.
  • Docs in English and Chinese: Environments "Preparation reuse", the Provider protocol, and the node generation protocol.

Measured

Copy throughput (mx2, real Environment: 51 MiB, about 320 files, one 47 MiB binary):

  • Owned disk, inside the guest: save about 0.4 s; restore 0.47 s copy in + 0.20 s extract + 0.09 s sync.
  • NFS bind, inside the guest: restore 1.09 s + 8.17 s, rejected as too slow. On the host: save 0.14 s, extract 0.65 s, works while the guest runs, owner and mode kept. This is the implemented path.

End to end on mx (fresh install of e01726b, microsandbox node mx2 with NFS workspace storage, one Template with an npm package, a setup command, an initial file, a Skill and env):

Session Harness Result restore / save ms create to ready s create to first text s
S1 codex miss, saved 90 / 152 31.1 33.5
S2 codex hit 315 / none 12.3 14.8
S3 claude_sdk hit 255 / none 18.2 22.2
S4 codex, one env value changed miss, saved 89 / 152 21.8 26.8
S5 codex, S1 entry aged 25 h miss, saved again 90 / 149 22.9 33.8

Every Turn saw the package, the setup output, the initial file and the Skill. The store is 0700 with 0600 entries owned by the node user, and an entry holds only initialization/, packages/ and workspace/. Hosted regression: codex 9/9 and claude_sdk 9/9. The first e2e run (b336d80) found the strict frame decoder rejecting the new fields; fixed in e01726b.

Tests

Core: hit, miss and failed save. Daemon: finalize rebinds an identical restored installation and rejects a different selection. Helper: an expired entry is not restored. Node: preparation request and response frames survive strict decoding. Failure paths (failed extract, save budget) were not exercised on a real VM.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Core computes a key from the Project, initial files and setup operations and calls RestorePreparation/SavePreparation on the Provider. On a hit only finalize runs. The microsandbox helper owns storage, a 24 hour TTL and an 8 GiB bound. The daemon rebinds an identical restored capability installation.
@SaladDay
SaladDay merged commit c2ed21d into main Oct 21, 2026
22 checks passed
@SaladDay
SaladDay deleted the prep-cache branch October 21, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant