Run agent tools remotely
In this example, we are going to let a hosted agent read and write customer files without giving the agent a customer cloud credential. The agent loop stays in your product; a Worker runs two reviewed tools against Storage in the selected customer deployment.
This pattern is useful when an agent needs access to data or services in a customer's environment. Your product invokes a named Command, the Worker performs that operation locally, and Alien returns the result.
The agent in your product invokes a named operation. A Worker in the customer environment runs the selected tool against private storage and returns the result.
We will create the Worker and Storage in alien.ts, implement the two tools in src/index.ts, and expose them as Commands. The Worker accepts this fixed tool list rather than arbitrary shell commands.
Describe the remote piece in alien.ts
const files = new alien.Storage("files").build()
const worker = new alien.Worker("worker")
.code({ type: "source", src: "./", toolchain: { type: "typescript" } })
.commandsEnabled(true)
.link(files)
.permissions("execution")
.build().link(files) gives this Worker a binding to files; it does not publish the bucket or inject an AWS, GCP, or Azure credential into your code. The permission profile limits the Worker to the storage actions declared by the stack.
Write the tools
const tools = {
"read-file": {
execute: async ({ path }: { path: string }) => {
const object = await storage("files").get(path)
return { content: new TextDecoder().decode(object.data) }
},
},
"write-file": {
execute: async ({ path, content }: { path: string; content: string }) => {
await storage("files").put(path, new TextEncoder().encode(content))
return { written: true, path }
},
},
}The Worker exposes this fixed list, not a shell. Adding another tool is a code change you can review.
Make the tools callable
command("execute-tool", toolSchema, async ({ tool, params }) => {
const handler = tools[tool]
if (!handler) throw new Error(`Unknown tool: ${tool}`)
return handler.execute(params)
})
command("list-tools", async () => Object.keys(tools))Run it locally
alien init remote-worker-ts
cd remote-worker-ts
alien dev
alien dev commands invoke --deployment default --command list-toolsStart with list-tools, then invoke execute-tool with read-file or write-file. Each local deployment gets its own Storage resource.
Put the tools beside customer data
alien releasePublishes a version. Nothing is deployed for a customer yet.
alien onboard acme-corpCreates a deployment link for that customer.
The customer opens the link and deploys into their environment.
Your hosted agent can now invoke these Commands against that deployment. The Worker reads and writes the customer's Storage; the agent receives only each tool result.
What you built
You kept the agent loop in your product and moved only two reviewed tools beside customer-owned Storage. This is the core remote-tools pattern: send a small operation to the data instead of giving the hosted agent direct storage credentials or copying the entire dataset back.
Source: examples/remote-worker-ts.
Next: Commands, Remote Bindings.