DEV Community

Sanchit
Sanchit

Posted on

Agent Harness Devlog #002

Building the Pluggable Sandbox

I'm building an agent harness, as a learning project and experimenting different ideas and implementations, along the way learning EffectTS, a lot of it is ideating with agents, agents do help a lot understanding libraries and frameworks which typically take more time and are involving.

Implementing Soft Sandbox

A soft sandbox solution is to implement some kind of application layered sandboxing, not hard sandbox and isolation solutions like VMs, containers, bubblewrap, etc.

This allows us to provided on-spot filesystem layer, for quick agentic workflows, without worrying about agent messing up the current filesystems.

I discovered @platformatic/vfs, a virtual filesystem provider for NodeJS, eventually vfs will be merged into official node, which is great.

The best part of using effect is composability, it's little magical and a blackbox, as I'm just learning about it, It's also very powerful.

The sandbox is just a layer which looks like

Layer<Provides> where Provides = Vfs | ChildProcessSpawner
Enter fullscreen mode Exit fullscreen mode

If your layer provides the tags, it plugs it. These are parts I feel kinda magical!

VFS allows for different provider implementation, like real filesystem, sqlite based, and in-memory filesystem, It also allows for custom provider implementation, so in future I can have S3 filesystem provider, and others.

Integrating with Just Bash

One of the cool projects from Vercel is just-bash It allows for sandboxed bash interpreter for agents, it implements some or most of the required coreutils functionality like grep, cat, ls, etc.

It's really powerful because agents love bash, they've been trained on 40+yrs of unix shell commands.

just-bash also provides a filesystem layer, like VFS but I think sticking to VFS helps, as it will later allows for future proofing with node:vfs implementation and custom provider implementations, the most value from just-bash is the bash interpreter, so the underlying FS could just be VFS and that's what I did, creating VFS implementation that has interface that satisfies just-bash, basically building the bridge

// just-bash accepts a custom filesystem interface.
// Implement it on top of the sandbox's VFS — don't let it bring its own.
const bridge = (vfs: VirtualFileSystem): IFileSystem => ({
  readFile:  (path) => vfs.promises.readFile(path, "utf8"),
  writeFile: (path, content) => vfs.promises.writeFile(path, content),
  stat:      async (path) => toStat(await vfs.promises.stat(path)),
  ...
Enter fullscreen mode Exit fullscreen mode

Bash is just a layer

const shell = Layer.effect(
  Shell,
  Effect.gen(function* () {
    const vfs = yield* FileSystem.Vfs;            // the sandbox's own tree
    const bash = new Bash({ fs: bridge(vfs), cwd: "/" });
    ...
Enter fullscreen mode Exit fullscreen mode

Composition is what really like with Effect like

EnvBash.layer(EnvInMemory.layer())        // bash over a throwaway memory tree
EnvBash.layer(EnvSqldb.layer("fs.db"))    // bash over a filesystem inside one sqlite file
...
Enter fullscreen mode Exit fullscreen mode

The VFS and just-bash working together

const filesystem = yield* FileSystem.Service;
const shell      = yield* Shell;

yield* filesystem.writeFileString("/data.txt", "alpha\nbeta\nbeta\n");

const result = yield* shell.exec("grep beta /data.txt | wc -l");
...
Enter fullscreen mode Exit fullscreen mode

So, if you like this scratchy non-edited, non-ai devlog, give it a like ;)

Next, I'm hoping to learn more about EffectTS and also go deep into building more!

Checkout the repo: https://github.com/codeworksh/codework
Other projects: https://codeworksh.github.io/aikit/

Top comments (0)