The code-first runtime for AI agents.
Define agent work in TypeScript. Run it in isolated Linux microVMs with durable workspaces and human input.
One TypeScript file.Image, Sandbox, Task, human input.
Codex here — or Claude Code, the AI SDK, any agent SDK that runs on Node. Durable continuation uses Actor input or independently completable Tokens; one-shot Task input remains an explicit start payload.
1import { image, sandbox, source, task, tokens } from "@helmr/sdk" 2import { Codex } from "@openai/codex-sdk" 3import { z } from "zod" 4 5const base = image("repo-agent") 6 .from("node:24-bookworm-slim") 7 .workdir("/workspace") 8 .run(["sh", "-ceu", "apt-get update && apt-get install -y git ripgrep"]) 9 .copy("/workspace/package.json", source.file("package.json"))10 .run(["bun", "install"])11 12export const repoSandbox = sandbox({ id: "repo-agent" })13 .image(base)14 .resources({ cpu: 2, memory: "4GiB" })15 16export const reviewPr = task({17 id: "review-pr",18 payload: z.object({ prNumber: z.number().int().positive() }),19 run: async (event, ctx) => {20 const codex = new Codex()21 const thread = codex.startThread({ workingDirectory: process.cwd() })22 const turn = await thread.run("Review this PR and propose a patch.")23 24 const approval = await tokens.create({ timeout: "30m" })25 await sendSlackApproval({26 callbackUrl: approval.callbackUrl27 })28 // The microVM freezes here — filesystem, memory, process.29 const decision = await approval.wait({30 schema: z.object({ approved: z.boolean() }),31 timeout: "30m",32 tags: ["approval", "github-review"],33 metadata: { subject: "Post this review to GitHub?" }34 }).unwrap()35 if (decision.approved) await postReview(event.prNumber, turn.finalResponse)36 }37})Workflows as functions. Typed in, typed out, durable in between.
Write the Task
export const reviewPr = task({
id: "review-pr",
payload: z.object({ prNumber: z.number() }),
run: async ({ prNumber }) => {
return draftReview(prNumber)
}
})One exported const with a typed payload and a run function. That is the whole unit Helmr deploys.
Start it from anywhere
const run = await client.tasks.start<typeof reviewPr>(
"review-pr",
{
payload: { prNumber: 482 },
workspace
}
)Your product, a webhook, or CI starts a deployed Task with a typed payload against an existing Workspace.
Put it on a cron
export const nightly = schedules.task({
id: "nightly-audit",
cron: {
pattern: "0 9 * * 1-5", timezone: "Asia/Tokyo"
},
workspace: { sandbox: repoSandbox },
run: async (_, ctx) => runAudit(ctx)
})The schedule lives beside the code and ships with it. Every fire gets a fresh Workspace.
Wait for a human
const approval = await tokens.create({ timeout: "30m" })
const decision = await approval.wait({
schema: z.object({ approved: z.boolean() }),
timeout: "30m",
tags: ["approval", "github-review"]
}).unwrap()The microVM freezes whole while it waits — filesystem, memory, process. A scoped callback completes one value.
Steerable agent sessions. Input and output, kept across Runs.
Define the Actor
export const reviewer = actor({
id: "reviewer",
async run(session) {
const input = await session.input
.receive({ idleTimeout: "30m" })
.unwrap()
await session.output.append({
type: "progress",
message: "Reviewing",
input
})
}
})Send input and read output
// From your product or webhook:
const session = client.sessions.ref(sessionId)
await session.input.send({
type: "steer",
instruction: "Please also update the tests."
}, { idempotencyKey: "slack:thread-1:message-7" })
const { records } = await session.output.list()
for (const record of records) {
render(record.sequence, record.data)
}Send a correction from Slack, your product, or the CLI. The Session history survives waits and continuation Runs.
Persistent VM filesystems. The same /workspace, Run after Run.
Define the environment
const base = image("repo-agent")
.from("node:24-bookworm-slim")
.workdir("/workspace")
.run(["npm", "install", "-g", "@openai/codex"])
export const repoSandbox = sandbox({
id: "repo-agent"
})
.image(base)
.resources({
cpu: 2,
memory: "4GiB"
})Choose the base image, install CLIs, and set the working directory and resources behind the Workspace.
Create the Workspace
const workspace = await client.sandboxes.createWorkspace(
"repo-agent",
{
key: `github-pr:${pr.id}`,
idempotencyKey: `workspace:${pr.id}`
}
)
const result = await workspace.exec({
command: ["bash", "-lc", "bun test"],
cwd: "/workspace",
idempotencyKey: `verify:${pr.id}`
})Create it once, run bounded commands, and attach later Task and Actor Runs to the same files.
Run on our cloud, or in your AWS.
Early, open, Apache 2.0. Read the source before you trust it with your repos.
Helmr Cloud coming soon
A managed fleet. Projects, environments, immutable deployments — no infrastructure to run.
Read the docsYour AWS account
The identical control plane and workers in your VPC, Apache 2.0. Credentials never leave your boundary.
Self-hosting guide