website/src/content/docs/actors/ai-and-user-generated-actors.mdx
import { faGithub } from "@rivet-gg/icons";
<CardGroup> <Card title="View Example on GitHub" href="https://github.com/rivet-dev/rivet/tree/main/examples/ai-and-user-generated-actors-freestyle" target="_blank" icon={faGithub}> Complete example showing how to deploy user-generated Rivet Actor code. </Card> </CardGroup>Deploying AI and user-generated Rivet Actors to sandboxed namespaces is useful for:
Traditional architectures require AI agents to coordinate across multiple disconnected systems: a database schemas, API logic, and synchronizing schemas & APIs.
With Rivet Actors, state and logic live together in a single actor definition. This consolidation means:
The deployment process involves four key steps:
<Step title="Create Cloud API Token">
1. Visit your project on [Rivet Cloud](https://dashboard.rivet.dev/)
2. Click on "Tokens" in the sidebar
3. Under "Cloud API Tokens" click "Create Token"
4. Copy the token for use in your deployment script
</Step>
<Step title="Install Dependencies">
Install the required dependencies:
```bash
npm install @rivetkit/engine-api-full@^25.7.2 freestyle-sandboxes@^0.0.95
```
</Step>
<Step title="Write Deployment Code">
Write deployment code that handles namespace creation, token generation, Freestyle deployment, and runner configuration. This can be called from your backend to deploy actor and frontend code to an isolated Rivet namespace.
```typescript
import { execSync } from "child_process";
import { RivetClient } from "@rivetkit/engine-api-full";
import { FreestyleSandboxes } from "freestyle-sandboxes";
import { prepareDirForDeploymentSync } from "freestyle-sandboxes/utils";
const CLOUD_API_TOKEN = "your-cloud-api-token";
const FREESTYLE_DOMAIN = "your-app.style.dev";
const FREESTYLE_API_KEY = "your-freestyle-api-key";
async function deploy(projectDir: string) {
// Step 1: Inspect API token to get project and organization
const { project, organization } = await cloudRequest("GET", "/tokens/api/inspect");
// Step 2: Create sandboxed namespace with a unique name
const namespaceName = `ns-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
const { namespace } = await cloudRequest(
"POST",
`/projects/${project}/namespaces?org=${organization}`,
{ displayName: namespaceName.substring(0, 16) },
);
const engineNamespaceName = namespace.access.engineNamespaceName; // NOTE: Intentionally different than namespace.name
// Step 3: Generate tokens
// - Runner token: authenticates the serverless runner to execute actors
// - Publishable token: used by frontend clients to connect to actors
// - Access token: provides API access for configuring the namespace
const { token: runnerToken } = await cloudRequest(
"POST",
`/projects/${project}/namespaces/${namespace.name}/tokens/secret?org=${organization}`,
);
const { token: publishableToken } = await cloudRequest(
"POST",
`/projects/${project}/namespaces/${namespace.name}/tokens/publishable?org=${organization}`,
);
const { token: accessToken } = await cloudRequest(
"POST",
`/projects/${project}/namespaces/${namespace.name}/tokens/access?org=${organization}`,
);
// Step 4: Build the frontend with public environment variables.
execSync("npm run build", {
cwd: projectDir,
env: {
...process.env,
VITE_RIVET_ENDPOINT: "https://api.rivet.dev",
VITE_RIVET_NAMESPACE: engineNamespaceName,
VITE_RIVET_TOKEN: publishableToken,
},
stdio: "inherit",
});
// Step 5: Deploy actor code and frontend to Freestyle with backend
// environment variables.
const freestyle = new FreestyleSandboxes({ apiKey: FREESTYLE_API_KEY });
const deploymentSource = prepareDirForDeploymentSync(projectDir);
const { deploymentId } = await freestyle.deployWeb(deploymentSource, {
envVars: {
RIVET_ENDPOINT: "https://api.rivet.dev",
RIVET_NAMESPACE: engineNamespaceName,
RIVET_TOKEN: runnerToken,
},
entrypoint: "src/backend/server.ts",
domains: [FREESTYLE_DOMAIN],
build: false,
});
// Step 6: Configure Rivet to run actors on the Freestyle deployment.
const rivet = new RivetClient({
environment: "https://api.rivet.dev",
token: accessToken,
});
await rivet.runnerConfigsUpsert("default", {
datacenters: {
"us-west-1": { // Freestyle datacenter is on west coast
serverless: {
url: `https://${FREESTYLE_DOMAIN}/api/rivet`,
headers: {},
runnersMargin: 0,
minRunners: 0,
maxRunners: 1000,
slotsPerRunner: 1,
requestLifespan: 60 * 5,
},
},
},
namespace: engineNamespaceName,
});
console.log("Deployment complete!");
console.log("Frontend:", `https://${FREESTYLE_DOMAIN}`);
console.log("Rivet Dashboard:", `https://dashboard.rivet.dev/orgs/${organization}/projects/${project}/ns/${namespace.name}`);
console.log("Freestyle Dashboard:", `https://admin.freestyle.sh/dashboard/deployments/${deploymentId}`);
}
async function cloudRequest(method: string, path: string, body?: any) {
const res = await fetch(`https://api-cloud.rivet.dev${path}`, {
method,
headers: {
Authorization: `Bearer ${CLOUD_API_TOKEN}`,
...(body && { "Content-Type": "application/json" }),
},
...(body && { body: JSON.stringify(body) }),
});
return res.json();
}
```
See the [example repository](https://github.com/rivet-dev/rivet/tree/main/examples/ai-and-user-generated-actors-freestyle) for the complete project structure including the template directory and build process.
For more information on Freestyle deployment, see the [Freestyle documentation](https://docs.freestyle.sh/web/overview).
</Step>
</Steps>
</Tab>
<Tab title="Rivet Self-Hosted">
<Steps>
<Step title="Prerequisites">
Before you begin, ensure you have:
- Node.js 18+ installed
- A [Freestyle](https://freestyle.sh) account and API key
- A [self-hosted Rivet instance](/docs/self-hosting) with endpoint and API token
</Step>
<Step title="Install Dependencies">
Install the required dependencies:
```bash
npm install @rivetkit/engine-api-full@^25.7.2 freestyle-sandboxes@^0.0.95
```
</Step>
<Step title="Write Deployment Code">
Write deployment code that handles namespace creation, Freestyle deployment, and runner configuration. This can be called from your backend to deploy actor and frontend code to an isolated Rivet namespace.
```typescript
import { execSync } from "child_process";
import { RivetClient } from "@rivetkit/engine-api-full";
import { FreestyleSandboxes } from "freestyle-sandboxes";
import { prepareDirForDeploymentSync } from "freestyle-sandboxes/utils";
// Configuration
const RIVET_ENDPOINT = "http://your-rivet-instance:6420";
const RIVET_TOKEN = "your-rivet-token";
const FREESTYLE_DOMAIN = "your-app.style.dev";
const FREESTYLE_API_KEY = "your-freestyle-api-key";
async function deploy(projectDir: string) {
// Step 1: Create sandboxed namespace using the self-hosted Rivet API
const rivet = new RivetClient({
environment: RIVET_ENDPOINT,
token: RIVET_TOKEN,
});
const namespaceName = `ns-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
const { namespace } = await rivet.namespaces.create({
displayName: namespaceName,
name: namespaceName,
});
// Step 2: Build the frontend with public environment variables.
execSync("npm run build", {
cwd: projectDir,
env: {
...process.env,
VITE_RIVET_ENDPOINT: RIVET_ENDPOINT,
VITE_RIVET_NAMESPACE: namespace.name,
VITE_RIVET_TOKEN: RIVET_TOKEN,
},
stdio: "inherit",
});
// Step 3: Deploy actor and frontend to Freestyle with backend
// environment variables.
const freestyle = new FreestyleSandboxes({ apiKey: FREESTYLE_API_KEY });
const deploymentSource = prepareDirForDeploymentSync(projectDir);
const { deploymentId } = await freestyle.deployWeb(deploymentSource, {
envVars: {
RIVET_ENDPOINT,
RIVET_NAMESPACE: namespace.name,
RIVET_TOKEN,
},
entrypoint: "src/backend/server.ts",
domains: [FREESTYLE_DOMAIN],
build: false,
});
// Step 4: Configure your self-hosted Rivet to run actors on the Freestyle
// deployment
await rivet.runnerConfigsUpsert("default", {
datacenters: {
"us-west-1": { // Freestyle datacenter is on west coast
serverless: {
url: `https://${FREESTYLE_DOMAIN}/api/rivet`,
headers: {},
runnersMargin: 0,
minRunners: 0,
maxRunners: 1000,
slotsPerRunner: 1,
requestLifespan: 60 * 5,
},
},
},
namespace: namespace.name,
});
console.log("Deployment complete!");
console.log("Frontend:", `https://${FREESTYLE_DOMAIN}`);
console.log("Freestyle Dashboard:", `https://admin.freestyle.sh/dashboard/deployments/${deploymentId}`);
}
```
See the [example repository](https://github.com/rivet-dev/rivet/tree/main/examples/ai-and-user-generated-actors-freestyle) for the complete project structure including the template directory and build process.
</Step>
</Steps>
</Tab>