Skip to content

Blog

The agent that builds your app should not publish it

Appaloft's new sandbox agent runtime lets coding agents build inside isolated, expiring sandboxes, then freezes their work into immutable artifacts that only an external actor can promote. Here is where we drew the boundary.

AppaloftAIAgentsSandboxDeployment

This week we shipped the two releases that turn Appaloft from a deployment control plane into something we now call an AI application delivery platform. v1.1.0 adds the execution sandbox platform and a sandbox agent runtime with a promotion workflow. v1.2.0 adds SDK resource handles so an application can drive the whole thing without hand-building API calls.

The target user is not someone deploying a side project. It is a developer building a product where a coding agent does the work: chat-to-app features, repository maintenance bots, support automation that edits code. The agent builds; Appaloft’s job is to make sure that what the agent built can be inspected, frozen, and deliberately shipped.

The most important design decision in the whole feature is also the simplest: the agent that produces the work is never the actor that publishes it.

A live workspace is not a deployable thing

Give an agent a shell and it will happily produce a running dev server. That demo is easy. What is hard is answering, afterwards, what exactly you would be shipping.

A live sandbox workspace can change between the moment you look at it and the moment you deploy it. A snapshot can capture runtime state that should never become deployment input. And an agent that can both produce code and push the publish button is one prompt injection away from shipping something nobody reviewed.

So we split the journey into separate objects with separate owners, and made the transitions explicit.

What runs where

A Sandbox in Appaloft is a controlled execution environment, not a VPS account handed to an agent. It has resource limits, a network policy that defaults to deny, file and process APIs, template provenance, an expiry time, and exact cleanup. The host that runs the sandbox provider is never exposed to the application developer or the agent.

An Agent Runtime belongs to exactly one Sandbox and dies with it. A Runtime admits at most one active Run at a time, and each Run is one submitted task with fresh or continue(parentRunId) context lineage. Your application keeps the chat and the session; Appaloft stores no hidden model reasoning. Run events are bounded, and credential, secret, password, token, and authorization fields are recursively redacted. They are an operational readback, not an audit log or a full transcript.

const sandbox = await appaloft.sandboxes.create({
  source: { kind: "template", templateId: process.env.APPALOFT_SANDBOX_TEMPLATE_ID! },
  requestedIsolation: "gvisor",
  limits: { cpuMillis: 2_000, memoryBytes: 2_147_483_648, diskBytes: 10_737_418_240, maxProcesses: 128 },
  networkPolicy: { mode: "deny", rules: [] },
  expiresAt: new Date(Date.now() + 60 * 60 * 1_000).toISOString(),
});

const agent = await sandbox.agents.create({ harness: "pi" });
const run = await agent.runs.create({ task: "Build the requested app in /workspace/app" });

The runtime is harness-neutral by design. Pi, Codex, Claude Code, and other harnesses all have vendor-specific session, event, and approval models, and none of those should become Appaloft’s public language. Harnesses implement an AgentHarnessPort; Pi is the first adapter, pinned by an immutable harness template and skill bundle digests, not a public API family. If we swap the harness later, the Sandbox → Runtime → Run ownership chain does not change.

Cancellation is deliberate too: the harness runs as a terminable background process, and cancelling a Run kills that process and blocks a late success result from overwriting the cancelled state.

Secrets never enter the sandbox

Production credentials must not appear in sandbox environment variables, files, run events, errors, or snapshots. When a run legitimately needs to reach something external, access goes through a destination-bound credential broker that fails closed on any destination, method, expiry, or transformation mismatch.

The same rule applies to authority. Confined work — files, processes, installs, tests, builds, dev servers — can run freely inside sandbox policy. Network expansion, credential grants, public port exposure, external writes, and promotion all require durable control-plane approval. A harness cannot approve itself, and an approval request carries the capability, destination, request digest, and expiry so your application can show a human exactly what is being asked.

Freeze first, preview the frozen thing, then promote

The path from workspace to production is three separate steps with three separate evidence points.

First, capture. With the sandbox idle and no active run, Appaloft validates the source root, hashes every file, and produces an immutable, content-addressed Source Artifact with a digest, an ordered manifest, and provenance. Capture rejects secrets, device and socket entries, unsafe links, and anything outside the source root.

Second, preview. A Candidate Preview is materialized from the exact artifact digest and reads only the artifact store — never the mutable live workspace. A dev server URL is not approval evidence; a preview of the exact frozen bytes is.

Third, promote. Promotion is a plan/accept pair:

const artifact = await appaloft.sandboxes.sourceArtifacts.create({ sandboxId, sourceRoot: "app" });
const preview = await appaloft.sandboxes.candidatePreviews.create({ artifactId: artifact.data.artifactId });
const plan = await appaloft.sandboxes.promotions.plan({
  sandboxId,
  artifactId: artifact.data.artifactId,
  expectedArtifactDigest: artifact.data.digest,
  candidatePreviewId: preview.data.previewId,
  target: { projectId, environmentId, destinationId, resourceName: "Generated app" },
});

if (preview.data.artifactDigest !== artifact.data.digest) throw new Error("digest mismatch");

The plan binds the artifact digest, the verified candidate, the target, and an expiry. Accepting it requires an unexpired plan, the expected digest, and an external actor with publish authority. The runtime and the harness identity cannot accept. In a real product you stop after plan, show the user the candidate URL and the exact digest, and call accept only from an explicit action outside the sandbox.

Acceptance is idempotent and asynchronous. The first promotion creates a Resource with a zip-artifact source binding and its first Deployment; a retry creates a new deployment attempt from the same artifact rather than a duplicate resource, and partial results are retained so a restart does not double-create anything.

Proof, and what it does not mean

A promotion is only completed when the associated deployment proof verdict is verified. That verdict chains together the artifact digest and provenance, the promotion plan and approval, deployment identity and readback, and machine-verifiable observations like route, health, and content correlation.

We want to be careful about the claim here. This chain proves what Appaloft can observe about delivery. It does not prove that agent-generated software is correct, secure, vulnerability-free, or compliant. Tests, review, scanning, and human approval remain separate gates. “Ship with proof” means you can check what was shipped and where it came from — not that the model was right.

Honest maturity labels

All of this is marked private preview in the docs, and the labels mean something specific:

  • The Pi adapter requires an operator-provisioned sandbox template pinned by version and digest, with APPALOFT_PI_SANDBOX_TEMPLATE_ID configured.
  • Candidate preview currently covers statically publishable output only.
  • Agent operations currently require a product session; a scoped long-lived application credential is not available yet.
  • Hosted worker, gVisor, internal-network, and gateway availability depends on your installation.

Meanwhile the Deploy & Verify half of the journey — folder, Git, zip, image, Docker, Compose, static artifact deployments with health, logs, retry, rollback, and proof readback — is available and unchanged. The sandbox work plugs into it rather than replacing it.

If you are building a product where an agent produces software, the runnable starting points are the Chat-to-App, human approval, and Preview-to-Promotion examples, alongside the sandbox, preview and promote, and delivery evidence docs.

The part we would most like feedback on is the approval surface: what would your product need to show a user before you would let them accept a promotion?