Freestyle Docs

Freestyle / Guides

Migrate from OpenShell to Freestyle

Move an OpenShell workload to a Freestyle VM, map inference routing to TLS transforms, and account for differences in policy and provider support.

Move your agent’s application and dependencies into a Freestyle VM, then configure its network access and model credentials from a trusted controller. You can retain an inference.local URL or let the application call the provider’s normal hostname with credentials injected at the edge.

This guide covers direct OpenAI and Anthropic HTTP inference, plus OpenRouter’s Chat Completions API. It maps the relevant OpenShell features and identifies policy or gateway behavior that needs a separate implementation before you cut over.

Why Migrate

Freestyle VMs are full Linux virtual machines designed for long-running, complex tasks. They are a good fit for coding and research agents that work for hours, days, or weeks, explore multiple approaches, and need to retain their environment’s state.

  • Fast startup. Start workers from prepared snapshots with their runtimes, dependencies, and application state already in place. New tasks can reuse a ready environment without repeating its setup.
  • Persistent workspaces. Keep an agent working for as long as its task needs. Pause preserves its running processes and memory so it can resume at the same point, even weeks later. This suits long-running work and tasks waiting for human input.
  • Powerful Linux environments. Use full hardware virtualization with nested virtualization, FUSE, eBPF, and Linux networking. The Ubuntu images run Docker and systemd, and larger VM sizes give complex workloads room for browsers, databases, and development tools.
  • Cheap snapshots and branching. Snapshot memory and disk with minimal interruption, then create multiple VMs from that exact state. Branch experiments, recover from failed attempts, or let research and reinforcement-learning agents explore several strategies from one checkpoint.
  • Built for multiple customers and private networks. Key workspaces by user with VM slugs, control access with identities, and isolate tenant networks with VPCs and firewall rules. WireGuard tunnels let agents reach your existing private infrastructure without exposing its services publicly.

Model access fits into the same workspace: scope TLS rules to a VM or VPC, choose its model, and rotate credentials while keeping provider keys outside the guest. Use OpenRouter when a workspace needs models from multiple providers through one gateway.

Use the policy and gateway comparison below to account for any OpenShell controls your workload also depends on.

Map Your Current Setup

Start with your OpenShell image, startup command, workspace files, network policy, provider configuration, and any interceptors or middleware. Record the HTTP paths the workload actually calls, including discovery, token counting, uploads, and streaming connections.

OpenShell configuration or operationFreestyle migration
Sandbox image and startup commandPrepare a VM snapshot containing the application; start its process with vm.exec() or a service.
openshell sandbox execVM exec for one-off commands, PTY for interactive processes.
Workspace filesCopy application files through VM files, Git, or SSH; rebuild OS and runtime dependencies in the VM.
Network endpoint grantsTLS rules for named HTTP egress and firewall rules for other network access.
Provider credential recordStore the credential in the controller’s secret store and supply it in a TLS header transform.
Selected inference modelJSON Patch add at /model on the generation endpoint.
Provider/model updateReplace the full TLS rule using freestyle.tls.rules.update.

OpenShell supports creating sandboxes from containers and directories; Freestyle boots VM snapshots. There is no OpenShell image or policy import in this recipe. Use NVIDIA’s sandbox lifecycle reference to inventory the operations you need to replace. If the application requires Docker, run its container inside the VM.

Prepare And Start The VM

Prepare an Ubuntu-based snapshot containing your application, its runtime and provider SDK, and ca-certificates. Install packages while the builder has the required network access. Copy application data, not OpenShell-managed proxy configuration, CA files, or provider secrets.

Run this TypeScript in your trusted controller after installing npm install freestyle@latest. Set FREESTYLE_API_KEY and FREESTYLE_SNAPSHOT_ID there:

import { Freestyle, type CreateTlsRuleOptions } from "freestyle";

function requiredEnv(name: string): string {
  const value = process.env[name]?.trim();
  if (!value) throw new Error(`Missing ${name}`);
  return value;
}

const freestyle = new Freestyle();
const { vm, vmId } = await freestyle.vms.create({
  snapshotId: requiredEnv("FREESTYLE_SNAPSHOT_ID"),
  firewall: { rules: [] },
});

const result = await vm.exec("pwd");
console.log({ vmId, stdout: result.stdout, statusCode: result.statusCode });

This VM begins without a broad public-egress grant. Add the named model route below before starting the agent, plus any explicit grants its tools need. For private repositories, use the Git credential injection guide.

Keep An Inference Alias

With the empty firewall above, use the direct-provider configuration from the OpenAI, Anthropic, or OpenRouter guide first. Host-alias rules currently omit the automatic edge firewall grant: the alias configuration below needs an existing allowed path to the edge or requests time out, even with the correct CA. A direct-provider rule with destination: { public: true } supplies that edge grant without broad public egress. This is a routing limitation, separate from container certificate trust.

OpenShell’s inference.local routing holds provider credentials and selects a model outside the sandbox. To preserve that URL for an OpenAI Responses client, add the following to the controller above. Supply OPENAI_API_KEY and OPENAI_MODEL only to the controller:

const options: CreateTlsRuleOptions = {
  action: "allow",
  domain: "inference.local",
  source: { vmId },
  destination: { host: "api.openai.com", port: 443 },
  match: { method: ["POST"], path: { exact: "/v1/responses" } },
  transform: [
    { headers: { authorization: `Bearer ${requiredEnv("OPENAI_API_KEY")}` } },
    { jsonPatch: [{ op: "add", path: "/model", value: requiredEnv("OPENAI_MODEL") }] },
  ],
};

const rule = await freestyle.tls.rules.create(options);
console.log({ ruleId: rule.id });

Freestyle configures the VM’s hostname resolution and system CA trust. Docker containers need their own CA and hostname setup; Python Requests and HTTPX need the appropriate bundle setting, even when curl already works in the VM. The edge forwards the original request path to the destination host, injecting the configured key and model only when the method/path match. It does not translate between provider protocols or add a base-path prefix.

Use the OpenAI guest example with baseURL: "https://inference.local/v1". The key and model placeholders stay the same. For other API surfaces, change the route and client together:

ClientGuest SDK baseURLDestination hostExact POST pathInjected header
OpenAI Responseshttps://inference.local/v1api.openai.com/v1/responsesauthorization: Bearer …
OpenAI Chat Completionshttps://inference.local/v1api.openai.com/v1/chat/completionsauthorization: Bearer …
Anthropic Messageshttps://inference.localapi.anthropic.com/v1/messagesx-api-key: …
OpenRouter Chat Completionshttps://inference.local/api/v1openrouter.ai/api/v1/chat/completionsauthorization: Bearer …

The Anthropic client adds /v1 itself and supplies anthropic-version; use its guest example. Retain the Node CA-bundle setting from the provider guides.

For OpenRouter, use the OpenRouter recipe, which also replaces the models fallback list. Its alias base URL includes /api/v1; changing only the destination host will not add the /api prefix.

These are alternative configurations for one alias. To expose more than one route to the same VM, assign separate aliases such as responses.internal and messages.internal, each with its own rule and SDK client. Different VMs can also use the same alias with VM-scoped rules selecting different backends. Two rules for the same source and domain do not dispatch by match; the edge selects a TLS rule before it evaluates the HTTP request conditions.

If preserving an alias is unnecessary, use the provider’s normal hostname with destination: { public: true }, as in the OpenAI and Anthropic guides. For OpenRouter, use openrouter.ai and retain /api/v1 in the SDK base URL.

Account For Policy And Gateway Differences

OpenShell denies unsupported inference paths and filters caller headers for its configured provider. Freestyle’s match only gates transforms: an unmatched request keeps its original headers and body and is forwarded. Header transforms overwrite specified headers; they do not implement an arbitrary header allowlist. If your application depends on endpoint denial or header filtering, retain a gateway providing those controls. See OpenShell inference routing and Freestyle request matching.

OpenShell’s policy can bind network access to binaries and configure filesystem/process restrictions. Freestyle TLS rules scope grants to a VM or VPC; every process within that scope can use them. VM isolation does not reproduce an OpenShell process policy. Rebuild required in-guest restrictions explicitly or separate workloads into VMs.

OpenShell’s provider adapters include cloud-specific signing and translation. A Freestyle header transform and JSON Patch do not replace Bedrock signing, Vertex token exchange, credential refresh, or custom interceptor code. Keep the necessary provider adapter in a service your VM can reach. Similarly, middleware that inspects responses or arbitrary body fields needs its own implementation.

The JSON recipe supports ordinary HTTP inference and SSE responses. It does not cover multipart uploads, JSONL batch files, or WebSocket sessions. Patching /model does not constrain nested batch or fallback models. Check transform limits before assuming a gateway extension can be replaced with a patch.

Rule updates can take about five seconds to reach cached edge decisions and do not interrupt requests already in flight. Do not rely on an update to terminate an existing stream. Rotation instructions are in each provider guide.

Verify Before Cutting Over

  1. Run the application’s startup command and a representative tool action in the new VM. Verify workspace files and required network grants.
  2. Send a small provider request with placeholder guest credentials. Verify the response’s model and provider usage, then exercise streaming if you use it.
  3. Exercise every additional endpoint the agent needs. A generation-only match will not inject credentials into discovery, token counting, or uploads.
  4. Check an unmatched path with a local test origin to confirm your expected behavior. If you need it denied, verify that your additional gateway denies it; do not treat missing injected credentials as a firewall decision.
  5. Change the model or rotate the key through the controller and verify a fresh request after cache refresh. Keep the prior deployment available until the workload passes these checks.

When ready, direct new work to the Freestyle VM. Retire the old OpenShell sandbox and provider grants through your normal process. Deleting a Freestyle TLS rule removes that grant; revoking the provider credential is a separate operation.

esc