Skip to main content
Every App has an isolated Linux sandbox (MicroVM) where you and your agents edit source files, run shell commands, manage Git commits, and test the App on a live dev server before publishing to production. This enables you to edit and create fully functional Apps, preview changes, and have full capability to build what you need. When you deploy an App, it will take what’s actively in the development environment and attempt to deploy that to production.

Sandbox lifecycle

You do not need to actively manage the development environment state. Judt manages the sandbox lifecycle automatically:
  • Stopped: When you create an App with POST /api/apps, its sandbox_status is "stopped".
  • Starts on demand: Any request that reads or changes the sandbox starts it automatically. On the first start, Judt initializes the /app working directory from the App’s template.
  • Stops when idle: After 5 minutes with no API actions and no preview requests, Judt commits any uncommitted changes in /app, saves a durable backup, and stops the sandbox.
  • Manual stop: If you want, you can stop a sandbox. Its not necessary. POST /api/apps/{id}/stop will commit changes, back up /app, and stop the sandbox immediately.

Which endpoints start the sandbox

Sandbox status values

The sandbox_status field on the App object has one of these values:

Environment and limits

Inside the sandbox, your App lives in /app:

Reserved paths

All file paths in the API are relative to /app and cannot start with / or contain ... The Files API blocks direct access to runtime, dependency, and Git metadata paths (400 reserved_path):
  • .celld
  • .dev.vars and .dev.vars.*
  • .env and .env.*
  • node_modules
  • .git
  • dist
  • .cache
The .agents/skills/judt-apps directory is read-only. You can read its files, but a write returns 400 reserved_path. To install packages in node_modules or build output into dist, run a shell command with POST /api/apps/{id}/commands. To set environment credentials, use Secrets.

Read and write files

List and search files

Call GET /api/apps/{id}/files to list files in /app, filter by glob, or search file contents:
When you pass content or pattern, each matching file in results includes match_count and up to 20 matches ([{ "line": 12, "text": "..." }]).

Read a file

Call GET /api/apps/{id}/files/{path} to read a file:
  • Text files: Returns JSON with path, size, binary: false, content, and line_count. It also includes lines when you pass ?lines=120, ?lines=120-180, or ?lines=120-.
  • Binary files: A JSON request returns metadata with binary: true and no content. Send Accept: application/octet-stream to download the raw bytes.
  • ETag caching: Every response includes an ETag header (the quoted SHA-256 hash of the file). Send If-None-Match: "<etag>" on later reads to receive 304 Not Modified when the file has not changed.

Write or delete a file

Call PUT /api/apps/{id}/files/{path} to create or replace a file (up to 1 MiB). Parent directories are created automatically.
  • Text files: Send Content-Type: application/json with {"content": "..."}.
  • Binary files: Send Content-Type: application/octet-stream with the raw file bytes as the request body.
  • Concurrency control: Send If-Match: "<etag>" to update the file only if its current ETag matches, or If-None-Match: * to create the file only if it does not exist yet. If the condition fails, the API returns 412 precondition_failed.
Call DELETE /api/apps/{id}/files/{path} to delete a file and clean up any empty parent directories. You can also pass If-Match: "<etag>" on DELETE.

Run shell commands

Call POST /api/apps/{id}/commands to run a shell command with Bash inside /app:
The command runs as editor in /app. It does not get the App’s Secrets, and its output shows any Secret value as [secret:NAME].
  • timeout_seconds: 1 to 120 seconds (default 60). If the command exceeds the timeout, the API terminates the process group and returns status: "timed_out".
  • status: If the command ends without a result, for example because the sandbox was lost, the API returns status: "interrupted" and exit_code is null. The effects of the command are unknown, and it does not run again.
  • exit_code: A non-zero exit code still returns HTTP 200 with status: "completed". Always check exit_code in the response body.
  • output: Combined stdout and stderr, up to 64 KiB (truncated: true if output exceeded 64 KiB).

Inspect Git status, commits, and restore

The /app directory is a Git repository.

Inspect uncommitted changes

Call GET /api/apps/{id}/git with a mode query parameter. The response has Git’s output in the output field:

Commit changes

Call POST /api/apps/{id}/commits with a single-line message (1 to 240 characters) to stage all changes in /app, create a Git commit, and save a durable backup.

Restore an earlier commit

Call POST /api/apps/{id}/restore with {"commit_id": "cmt_..."} to reset the sandbox working tree (/app) to that commit. Restoring a commit updates the sandbox only; it does not change what is running in production until you deploy.

Next steps