Skip to content

Commit 64eae99

Browse files
authored
refactor(sandbox): remove runtime file projection (#91)
## Summary - remove the unconsumed `/workspace/.cheatcode/runtime.json` projection - remove every best-effort provider write triggered by process start, restart, reconciliation, kill, status, and sandbox reset - keep Durable Object process records as the single lifecycle authority - remove documentation for the non-portable file ## Why Production QA proved Daytona's persistent-volume toolbox and process views do not provide a coherent root-level file projection for this path. The file has no runtime consumer and was explicitly non-authoritative, so retaining repeated best-effort writes would add provider calls and warnings without giving users a reliable artifact. A clean implementation keeps the authoritative Durable Object state only. ## Verification - `pnpm turbo lint typecheck build` — 76/76 tasks passed on Node 24.18.0 - affected architecture boundary check — passed, 103 modules / 194 dependencies - affected Knip workspace — passed - no remaining `runtime.json` or manifest-sync references - `git diff --check` — passed - exactly one Drizzle migration remains; no database changes
1 parent 33a3b18 commit 64eae99

5 files changed

Lines changed: 0 additions & 104 deletions

File tree

apps/agent-worker/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,6 @@ manifest avoids rewriting unchanged packages and limits cleanup to files previou
133133
managed by that package, preserving local dependencies and generated output. Curated
134134
default skills are immutable snapshot files under `/home/node/.cheatcode/default-skills/`.
135135

136-
ProjectSandbox also writes `/workspace/.cheatcode/runtime.json` as a generated projection of
137-
managed app-preview processes through Daytona's filesystem API. The Durable Object process records
138-
remain authoritative; the file is only an inspectable runtime manifest.
139-
140136
Managed processes use required stable IDs and a maximum of 32 live metadata slots per user
141137
sandbox. Reusing an ID atomically replaces that slot. At capacity, ProjectSandbox reconciles the
142138
bounded record set against Daytona, removes missing or completed sessions and their port state,

apps/agent-worker/src/durable-objects/project-sandbox-lifecycle.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import {
4747
} from "./project-sandbox-workspace-state";
4848

4949
const ClearWorkspaceEvidenceSchema = z.object({ cleared: z.literal(true) }).strict();
50-
const RUNTIME_MANIFEST_PATH = "/workspace/.cheatcode/runtime.json";
5150
const RUNTIME_RESET_PENDING_KEY = "sandbox_runtime_reset_pending";
5251
const SKILL_RUNTIME_DIRECTORY = "/workspace/.cheatcode/runtime";
5352

@@ -682,7 +681,6 @@ export abstract class ProjectSandboxLifecycle extends DurableObject<ProjectSandb
682681
return;
683682
}
684683
try {
685-
await client.deleteFilePath(sandboxId, RUNTIME_MANIFEST_PATH, false);
686684
await client.deleteFilePath(sandboxId, SKILL_RUNTIME_DIRECTORY, true);
687685
await this.ctx.storage.delete(RUNTIME_RESET_PENDING_KEY);
688686
} catch (error) {

apps/agent-worker/src/durable-objects/project-sandbox-processes.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ import {
6161
type ProjectStartProcessInput,
6262
ProjectStartProcessInputSchema,
6363
} from "./project-sandbox-runtime";
64-
import { writeSandboxRuntimeManifest } from "./project-sandbox-runtime-manifest";
6564

6665
const DEFAULT_EXEC_TIMEOUT_MS = 60_000;
6766

@@ -76,8 +75,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
7675

7776
public async ensureReady(): Promise<ProjectSandboxStatus> {
7877
const result = await this.runCode({ code: "print('ready')", language: "python" });
79-
const id = await this.existingSandboxId();
80-
if (id) await this.syncRuntimeManifestBestEffort(id);
8178
return {
8279
healthy: result.success,
8380
ping: result.stdout.trim(),
@@ -198,12 +195,10 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
198195
);
199196
} catch (error) {
200197
await this.cleanupLaunchedProcess(id, sessionId, name);
201-
await this.syncRuntimeManifestBestEffort(id);
202198
throw error;
203199
}
204200
const record = { ...provisionalRecord, cmdId: exec.cmdId ?? sessionId };
205201
await this.persistStartedProcess(id, name, record, parsed.waitForPort);
206-
await this.syncRuntimeManifestBestEffort(id);
207202
await recordSandboxUsageBestEffort(await this.meteringContext());
208203
return { command: record.command, id: name, status: "running" };
209204
}
@@ -299,7 +294,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
299294
await this.client().deleteFilePath(id, ENV_FILE_DIR, true);
300295
}
301296
await this.ctx.storage.delete(PROCESS_PORT_ALLOC_KEY);
302-
if (id) await this.syncRuntimeManifestBestEffort(id);
303297
return killed;
304298
}
305299

@@ -317,7 +311,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
317311
await this.ctx.storage.delete(`${PROC_PREFIX}${processId}`);
318312
await this.releaseProcessPort(processId);
319313
}
320-
if (id) await this.syncRuntimeManifestBestEffort(id);
321314
return { processId, status: "killed", success: true };
322315
}
323316

@@ -335,7 +328,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
335328
if (isMissingDaytonaProcessError(error)) {
336329
await this.ctx.storage.delete(`${PROC_PREFIX}${process.name}`);
337330
await this.releaseProcessPort(process.name);
338-
await this.syncRuntimeManifestBestEffort(id);
339331
return null;
340332
}
341333
throw this.toUpstreamError(error, "Sandbox console read failed.");
@@ -379,10 +371,8 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle {
379371
cmdId: exec.cmdId ?? sessionId,
380372
startedAtMs: Date.now(),
381373
} satisfies ProcessRecord);
382-
await this.syncRuntimeManifestBestEffort(id);
383374
} catch (error) {
384375
await this.cleanupLaunchedProcess(id, sessionId, name);
385-
await this.syncRuntimeManifestBestEffort(id);
386376
throw error;
387377
}
388378
}
@@ -687,16 +677,6 @@ cd ${shellQuote(cwd)} && ${rawCommand}`;
687677
await this.ctx.storage.delete(`${PROC_PREFIX}${name}`);
688678
}
689679

690-
private async syncRuntimeManifestBestEffort(id: string): Promise<void> {
691-
const records = await this.ctx.storage.list({ prefix: PROC_PREFIX });
692-
await writeSandboxRuntimeManifest(this.client(), id, records).catch((error: unknown) => {
693-
createLogger().warn("sandbox_runtime_manifest_sync_failed", {
694-
error,
695-
sandboxId: this.sandboxName(),
696-
});
697-
});
698-
}
699-
700680
private async deleteSessionEnvironment(id: string, sessionId: string): Promise<void> {
701681
await this.client().deleteFilePath(id, `${ENV_FILE_DIR}/${sessionId}.env`, false);
702682
}

apps/agent-worker/src/durable-objects/project-sandbox-runtime-manifest.ts

Lines changed: 0 additions & 74 deletions
This file was deleted.

infra/containers/sandbox/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,6 @@ is canonical in R2 and mirrored completely to
154154
source, schemas, references, templates, and common binary assets; dependency
155155
folders, virtual environments, caches, locks, and build output remain sandbox-local.
156156

157-
`/workspace/.cheatcode/runtime.json` is generated from Durable Object-managed
158-
preview process state. It is a human-readable projection only; sandbox code
159-
must never treat it as the lifecycle authority.
160-
161157
Cheatcode does not deploy or synchronize generated user apps. The curated
162158
catalog therefore has no deploy skill, deploy runtime, or app-side Composio
163159
bridge. Connected-app skills invoke the existing request-scoped Composio tools

0 commit comments

Comments
 (0)