the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rename sandboxId field and use params for RPC

Rename schema property sandbox_id to sandboxId while keeping the DB
column as sandbox_id. Update server handlers to use record.sandboxId
for start/stop calls. Convert client calls to pass id via params and
include Authorization headers. Minor CLI list UX tweak for RUNNING
status.

+70 -11
+4 -2
apps/api/src/schema/sandboxes.ts
··· 9 9 import users from "./users"; 10 10 11 11 const sandboxes = pgTable("sandboxes", { 12 - id: text("id").primaryKey().default(sql`sandbox_id()`), 12 + id: text("id") 13 + .primaryKey() 14 + .default(sql`sandbox_id()`), 13 15 base: text("base"), 14 16 name: text("name").unique().notNull(), 15 17 displayName: text("display_name"), ··· 30 32 status: text("status").notNull(), 31 33 keepAlive: boolean("keep_alive").default(false).notNull(), 32 34 sleepAfter: text("sleep_after"), 33 - sandbox_id: text("sandbox_id"), 35 + sandboxId: text("sandbox_id"), 34 36 installs: integer("installs").default(0).notNull(), 35 37 startedAt: timestamp("started_at"), 36 38 createdAt: timestamp("created_at").defaultNow().notNull(),
+1 -1
apps/api/src/xrpc/io/pocketenv/sandbox/startSandbox.ts
··· 45 45 ? ctx.cfsandbox(record.base!) 46 46 : ctx.sandbox(); 47 47 48 - await sandbox.post(`/v1/sandboxes/${params.id}/start`, undefined, { 48 + await sandbox.post(`/v1/sandboxes/${record.sandboxId}/start`, undefined, { 49 49 headers: { 50 50 Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 51 51 },
+1 -1
apps/api/src/xrpc/io/pocketenv/sandbox/stopSandbox.ts
··· 45 45 ? ctx.cfsandbox(record.base!) 46 46 : ctx.sandbox(); 47 47 48 - await sandbox.post(`/v1/sandboxes/${params.id}/stop`, undefined, { 48 + await sandbox.post(`/v1/sandboxes/${record.sandboxId}/stop`, undefined, { 49 49 headers: { 50 50 Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 51 51 },
+11 -2
apps/cli/src/cmd/list.ts
··· 23 23 ); 24 24 25 25 const response = await client.get<{ sandboxes: Sandbox[] }>( 26 - `/xrpc/io.pocketenv.actor.getActorSandboxes?did=${profile.data.did}&offset=0&limit=100`, 26 + "/xrpc/io.pocketenv.actor.getActorSandboxes", 27 + { 28 + params: { 29 + did: profile.data.did, 30 + offset: 0, 31 + limit: 100, 32 + }, 33 + }, 27 34 ); 28 35 29 36 const table = new Table({ ··· 60 67 table.push([ 61 68 chalk.greenBright(sandbox.name), 62 69 sandbox.baseSandbox, 63 - sandbox.status, 70 + sandbox.status === "RUNNING" 71 + ? chalk.greenBright(sandbox.status) 72 + : sandbox.status, 64 73 dayjs(sandbox.createdAt).fromNow(), 65 74 ]); 66 75 }
+14
apps/cli/src/cmd/start.ts
··· 1 1 import consola from "consola"; 2 2 import chalk from "chalk"; 3 + import getAccessToken from "../lib/getAccessToken"; 4 + import { client } from "../client"; 5 + import { env } from "../lib/env"; 3 6 4 7 async function start(name: string) { 8 + const token = await getAccessToken(); 9 + 10 + await client.post("/xrpc/io.pocketenv.sandbox.startSandbox", undefined, { 11 + params: { 12 + id: name, 13 + }, 14 + headers: { 15 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 16 + }, 17 + }); 18 + 5 19 consola.success(`Sandbox ${chalk.greenBright(name)} started`); 6 20 consola.log( 7 21 `Run ${chalk.greenBright(`pocketenv console ${name}`)} to access the sandbox`,
+14
apps/cli/src/cmd/stop.ts
··· 1 1 import chalk from "chalk"; 2 2 import consola from "consola"; 3 + import getAccessToken from "../lib/getAccessToken"; 4 + import { client } from "../client"; 5 + import { env } from "../lib/env"; 3 6 4 7 async function stop(name: string) { 8 + const token = await getAccessToken(); 9 + 10 + await client.post("/xrpc/io.pocketenv.sandbox.stopSandbox", undefined, { 11 + params: { 12 + id: name, 13 + }, 14 + headers: { 15 + Authorization: `Bearer ${env.POCKETENV_TOKEN || token}`, 16 + }, 17 + }); 18 + 5 19 consola.success(`Sandbox ${chalk.greenBright(name)} stopped`); 6 20 } 7 21
+25 -5
apps/web/src/api/sandbox.ts
··· 27 27 28 28 export const claimSandbox = ({ id }: { id: string }) => 29 29 client.post<{ sandbox: Sandbox | undefined }>( 30 - `/xrpc/io.pocketenv.sandbox.claimSandbox?id=${id}`, 30 + "/xrpc/io.pocketenv.sandbox.claimSandbox", 31 31 undefined, 32 32 { 33 + params: { 34 + id, 35 + }, 33 36 headers: { 34 37 Authorization: `Bearer ${localStorage.getItem("token")}`, 35 38 }, ··· 38 41 39 42 export const getSandbox = (id: string) => 40 43 client.get<{ sandbox: Sandbox | undefined }>( 41 - `/xrpc/io.pocketenv.sandbox.getSandbox?id=${id}`, 44 + "/xrpc/io.pocketenv.sandbox.getSandbox", 45 + { 46 + params: { 47 + id, 48 + }, 49 + headers: { 50 + Authorization: `Bearer ${localStorage.getItem("token")}`, 51 + }, 52 + }, 42 53 ); 43 54 44 55 export const getSandboxes = (offset?: number, limit?: number) => ··· 56 67 ); 57 68 58 69 export const stopSandbox = (id: string) => 59 - client.post(`/xrpc/io.pocketenv.sandbox.stopSandbox?id=${id}`, undefined, { 70 + client.post("/xrpc/io.pocketenv.sandbox.stopSandbox", undefined, { 71 + params: { 72 + id, 73 + }, 60 74 headers: { 61 75 Authorization: `Bearer ${localStorage.getItem("token")}`, 62 76 }, 63 77 }); 64 78 65 79 export const deleteSandbox = (id: string) => 66 - client.post(`/xrpc/io.pocketenv.sandbox.deleteSandbox?id=${id}`, undefined, { 80 + client.post("/xrpc/io.pocketenv.sandbox.deleteSandbox", undefined, { 81 + params: { 82 + id, 83 + }, 67 84 headers: { 68 85 Authorization: `Bearer ${localStorage.getItem("token")}`, 69 86 }, 70 87 }); 71 88 72 89 export const startSandbox = (id: string) => 73 - client.post(`/xrpc/io.pocketenv.sandbox.startSandbox?id=${id}`, undefined, { 90 + client.post("/xrpc/io.pocketenv.sandbox.startSandbox", undefined, { 91 + params: { 92 + id, 93 + }, 74 94 headers: { 75 95 Authorization: `Bearer ${localStorage.getItem("token")}`, 76 96 },