Sandbox runtime
Technical appendix: how nicoolAI runs workspace, schedule, Google Drive, and cron work inside Vercel Sandbox.
This page is part of the technical appendix.
It explains the current nicoolAI execution substrate: one Vercel Sandbox filesystem per work scope, with scope-owned workspace state and user-owned credentials checked at the moment a tool call needs them.
One execution substrate
nicoolAI has one model-facing bash tool and one execution backend.
Everything the agent executes runs inside Vercel Sandbox. There is no separate lightweight bash backend. The model sees paths and files; it does not choose infrastructure.
The important roots are:
/workspacefor repo, code, and ordinary workspace files/schedulesfor schedule JSON projected from Convex and diffed back through validated mutations/gdrivefor materialized Google Drive files and handles
All three roots live in the same sandbox filesystem for the current work scope.
Work scopes
nicoolAI keeps one sandbox per smallest useful unit of work.
Common scopes are:
user_personalfor a user's personal web, MCP, WhatsApp DM, and other direct personal workpersona_ownerfor persona surfaces where the owner's workspace and subscription fund guest conversationsroom_threadfor collaborative Slack or Discord-style room threadscron_runfor an individual scheduled execution
Sandbox names are derived from deterministic work-unit keys. The database does not store sandbox liveness. Vercel answers whether a derived sandbox is already warm, needs to resume, or needs to boot.
sandboxWorkUnits is the registry for configuration, not heartbeat state. It records things such as retention, rollback pointer, status, and command lock state.
Lifecycle
Sandboxes are kept alive after turns instead of eagerly stopped.
The runtime derives the sandbox name and calls getOrCreate. If the sandbox is warm, the next command lands in the same filesystem. If it timed out, Vercel resumes the persistent sandbox from the latest state or snapshot.
This avoids round-tripping active-sandbox state through Convex and makes liveness a property of the execution provider rather than application data.
Collaborative thread sandboxes are intentionally shorter lived. A TTL sweeper expires old thread work units, and keeper graduation lets a useful artifact survive by posting it back into the room thread and channel memory.
Ownership model
The runtime separates four kinds of ownership.
| Thing | Owner | Runtime rule |
|---|---|---|
| Sandbox filesystem | work scope | Personal work belongs to the user scope; room work belongs to the thread scope; cron work belongs to the cron run. |
| Memory | channel or user | Room memory is channel/thread-scoped; personal memory is user-scoped. |
| Connectors | user | Google Drive, GitHub, and MCP connections are checked per tool call against the current caller. |
| Subscription funding | user | A turn never spends another user's Codex subscription unless the surface class explicitly makes that user the funding actor. |
That distinction matters most in collaborative surfaces.
In Slack or Discord-style rooms, the thread sandbox can contain shared context, but live connector reads and refreshes still run as the caller. A cached file may remain readable as thread context, while a fresh Google Drive refresh can be denied for the next caller if that caller has not connected or shared access.
In persona surfaces such as WhatsApp or email, the persona owner funds the turn. Guests can converse, but they do not silently borrow arbitrary connector access; connector operations still pass through the authorization choke point.
Funding and nudges
Funded agent work requires an active connected Codex subscription for the turn's funding actor.
The funding actor depends on the surface:
- personal surfaces are caller-funded
- collaborative room surfaces are caller-funded
- persona surfaces are owner-funded
- cron runs are creator-funded from the creator snapshot captured at schedule creation
If no subscription is available, the runtime refuses the work and returns a connect-your-plan nudge. It does not fall back to a gateway model or spend a different user's tokens.
Google Drive mounts
Google Drive content is materialized under /gdrive inside the same sandbox filesystem.
The runtime resolves the caller, authorizes the operation, lists active Google Drive connections or shared scope records, and writes supported files and handles into paths under /gdrive/<connection-name>.
The practical outcome is:
- Docs and Slides are exposed as plain text
- metadata sidecars are available when needed
- unsupported files fail explicitly
- missing or ambiguous access defaults to deny
scopeShares records make shared context possible without turning the original user's connector into ambient room power. Snapshot-style shared content can be reused in the scope. Live reads, refreshes, and lazy rehydration are checked against the current caller.
Schedules
Schedule configuration lives in Convex and is projected into /schedules as JSON files when the sandbox turn starts.
When the agent edits those files, the runtime diffs the sandbox copy back through validated schedule mutations. The filesystem view is a convenience surface, not the source of authority.
Scheduled jobs use the unified scheduledJobs table. Legacy schedule storage is not part of the runtime model.
Crons
Crons are triggered by Convex and executed by Vercel.
Convex claims due jobs and hands execution to the Vercel-side cron executor. The executor derives the target work unit, acquires the sandbox, runs the job, and records the result back to Convex.
Cron funding is creator-funded. The creator actor and relevant target context are snapshotted when the schedule is created. If the creator later loses access or the required subscription is unavailable, the run is blocked and the creator is notified instead of falling back open.
Command serialization
Each sandbox work unit has one command slot.
The runtime uses a database-backed turn hold and lock renewal so overlapping web, room, MCP, or cron commands for the same sandbox do not interleave filesystem writes. When the workspace is busy, the user-facing path should say that the command is queued rather than implying a second sandbox was created.
Snapshots, rollback, and retention
Snapshots are for resumability, rollback, and retention. They are not a second workspace model.
Persistent sandboxes can be restored after timeout, and selected snapshots can be retained according to work-unit configuration.
The retention model is:
keepLastSnapshotskeeps a bounded number of recent snapshots- configurable expiry controls how long retained snapshots stay restorable
- thread sandboxes default to a short TTL, currently seven days
- personal and persona work can use longer retention windows
Rollback uses the work unit's current snapshot pointer. It does not promote a global master workspace.
GitHub auth attachment
GitHub follows the same connector ownership rule as Google Drive.
When GitHub workflows are wired into sandbox execution, the real credential stays in trusted server-side code. The sandbox and model must not receive raw tokens in prompt text, environment variables, files, or command arguments.
Access should be attached only for approved GitHub operations and only for the caller who owns the connection.
Fail-closed rules
Runtime access defaults to deny.
The important guards are:
- role resolution failure means no restricted skills
- missing role grants mean no restricted skills
- missing connector authorization means no live connector operation
- missing funding subscription means no funded agent work
- cron actor drift blocks the run
- room context never grants another caller's live connector