EPISODE 1943 [INTRODUCTION] [0:00:00] ANNOUNCER: AI agents have shown remarkable potential to function as persistent digital assistants that are capable of monitoring data, managing communications, and taking action autonomously over long periods. OpenClaw was one of the first serious attempts to fulfill that vision, connecting frontier coding agents to messaging platforms like Slack and WhatsApp and letting them run continuously in the background. However, OpenClaw largely set aside questions of security to pursue that vision, leaving credentials exposed in the agent's environment and giving agents broad access to data and services far beyond what any given task required. NanoClaw is an open- source project that takes a zero trust approach to agent orchestration. Rather than relying on instructions to constrain agent behavior, it isolates each agent in its own Docker container, keeps credentials entirely outside the agent's environment, and enforces human in the loop approval for sensitive actions. Gavriel Cohen is the founder of NanoClaw, and he joins Kevin Ball to discuss the security architecture behind NanoClaw. How the agent sandbox and proxy model work in practice, how agents communicate with each other and with the host orchestration process, how the project approaches context window management and long-lived agent sessions and more. Kevin Ball or KBall is the Vice President of Engineering at Mento and an independent coach for engineers and engineering leaders. He co-founded and served as CTO for two companies, founded the San Diego JavaScript Meetup, and organizes the AI in Action discussion group through Latent Space. Check out the show notes to follow KBall on Twitter or LinkedIn, or visit his website, kball.llc. [INTERVIEW] [0:01:53] KB: Gavriel, welcome to the show. [0:01:55] GC: Thank you. Great to be here. [0:01:57] KB: Yeah, I'm excited to dig in with you. This is a topic I was very excited to get the opportunity to discuss. But before we do, let's start with you a little bit. Can you share just a quick overview of your background and how you came to build NanoClaw? [0:02:09] GC: Absolutely. I studied physics and computer science at Tel Aviv University. And actually, during university, I started to work at wix.com as a student. I worked there as a software developer. Started in front end, moved over to full stack. And then led a team of developers there. Spent a total of about seven years. Actually, stopped programming for a few years and took a break and worked in public relations and promoted tech companies. And then jumped back in about a year and a half ago or a year and two months ago right around when Claude Code came out. I felt like there's this huge opportunity, I got to dive back in. Started building things. And that's when I got to Nano. [0:02:51] KB: So for those who may not be familiar, I think a lot more folks have heard of OpenClaw at this point, but what is NanoClaw? Let's just give the quick TLDR. [0:03:00] GC: NanoClaw is an open-source project, and it is a safe, secure alternative to OpenClaw. OpenClaw is this wild experiment. The way I see it, it's this wild experiment of if I put aside all of the security, safety, and even software quality concerns, I just put them aside and try to see can I get a lot of value if I just take frontier coding agents and connect them to everything. And the answer is you can get a ton of value. I used OpenClaw, I was building an AI-native marketing agency, and I set up OpenClaw on a chat with me and my co-founder and told it you've got the sales data from our company mounted in your environment. Look at that, and you're managing our sales pipeline. You're now our sales manager. And it very quickly started to do the work of an employee. And what that means is giving us a morning briefing. Here are the deals. Here are the things you need to follow up on. Setting reminders. We're just dumping raw data at it, and it's making sense of it and updating files. But then very quickly I saw these massive security issues. So that's why I sat down to build NanoClaw so I can get the value that I saw in OpenClaw but without compromising on safety and security. [0:04:19] KB: I think this is something I've definitely had on my eye. Since OpenClaw came out, I was like, "Oh, this is a disaster waiting to happen." It's fascinating. And I think we've seen some of that played out. But let's talk about the approach you take in NanoClaw. How do you make it secure? What is the security model that makes this work better? [0:04:36] GC: Yeah, OpenClaw is definitely this disaster unfolding that you can't look away. But for NanoClaw, the mindset is, first of all, agents can't be trusted. AI in general, it's non-deterministic. No matter how many exclamation points you put after the big bold instructions saying, "Don't delete my production database." I've joked that if you're digging through a codebase and you see in the claude.md file at the top in big bold letters, it says, "Never, never run, drop production DB," then you know that that agent has deleted a DB before and that it's going to do it again because it still can if the instruction is there, right? The idea is don't trust agents. Actually, approach it with a zero-trust mindset of saying, "As long as your agent is able to interact with any kind of unsanitized data." If it's looking at emails, if it's looking at pull requests, that's unsanitized data. People can stick in their prompt injections. And it means that your agent can be prompt injected, and it can act against you. It can end up turning out to be malicious. You need to treat the agent as if it's malicious. With NanoClaw, we isolate the agents. Each agent is running in its own sandbox, isolated from the host machine, isolated from other agents. And we're very intentional about what we put in the agent's environment. First step is isolate it. Second step, don't put any credentials, secrets, API keys, tokens into the agent's environment. Now, you do want to give the agent the ability to interact with credentialed services and APIs. So, the credentials, tokens, API keys sit outside of the agent's environment. All requests that are leaving the agent's environment get proxied through a small vault that sits next to the agent, and credentials get injected outside of the agent's environment. That's the second part. No credentials or secrets in the agent's environment. And then the third part is enforcing policies and access control at that proxy gateway point, and including human-in-the-loop approval. I can connect my agent to my email, for example. The agent doesn't hold the actual credentials that allow it to access the email, but its requests get proxied, credentials get added. And I can set a policy saying it can read my emails freely. But if it tries to send an email or delete an email, that requires my approval. And then an approval request gets sent to me, and I need to approve each action. [0:07:13] KB: This sandboxing and proxy approach is something I feel like I've seen bubbling up in a number of places as people grapple with, yeah, this core problem that agents cannot be trusted. LLMs on their own can only sort of be trusted. But then once you introduce any sort of outside influence, it's like dealing with user-generated content again, right? You can't trust it. You've got to sanitize in some form. And here, sanitization looks like it's isolated. Can we dive into the details? How do you isolate it? You said it's in its own container, but what does that end up looking like? What is the interface to the proxy? How do all those pieces work? [0:07:48] GC: We have the agents running in Docker containers. There's also an option to run it in Docker sandboxes, which is a new thing that Docker has been working on specifically for running agents, and that has some extra hardening. And the agent runs in that environment. It gets a folder mounted, and that's its file system. So it can create files, it can create folders, it can organize them in all kinds of ways. It can manipulate its environment in any way. The approach that we took with NanoClaw is not trying to inspect every action and every request, but let the agent run wild within its environment and then enforce things on the boundary of that environment. You mount a file system, one NanoClaw instance can run on a machine in a VM, say, and have many agents running in that one instance. There's a host process that's responsible for orchestrating the different agents and containers and routing the messages to the right container with the right agent with the right session. And then the way it's implemented, there are two files that are two SQLite DBs, one for the agents inbox and one for the agent's outbox. The host process, when it gets a message and determines that it's supposed to be routed to an agent, agent A, it writes the message into the DB that's mounted for that agent. And the agent is pulling the DB for new messages every time. It's actually not the agent to be more precise. It's a loop. There's a little process running inside the sandbox. It's pulling the inbox every time a new message arrives. It just pushes it to the agent. And that's by default agent SDK, Claude's, Anthropic's agent SDK. It can also run Codex or OpenCode. Agent does its thing, uses tools, bash commands, whatever it wants to do going wild. It can do all kinds of wild stuff in its environment, but it can't access the host machine or other agents' environments. And then when the agent finishes and outputs a response, the little process running in the sandbox for the agent writes that to the agent's outbox. And the host process is pulling the outbox gets the response and routes it to the correct chat. That could be a Slack channel, it could be a Slack DM, could be a WhatsApp group, wherever it's supposed to go to. [0:10:16] KB: Interesting. So those input and output SQLites, they're only used for input messages in both directions? [0:10:22] GC: Yes. And we made a decision that everything is messages. There are a couple environment variables that are injected into the container. Besides that, everything going into the agent's environment, everything coming out is set as messages. For example, if I want to do a schedule task, I have the agent run at a certain time every day and send me a briefing of my sales data, my sales pipeline. That's a message with a process after time. And if I want it to be a recurring task, then it's a message with process after and the certain recurrence set to it. Everything is messages. Approval requests are responses to approval requests. All of that is just messages or system messages or regular messages, but everything is messages. [0:11:13] KB: Fascinating. And why have the external process managing that rather than the agent directly sending messages? [0:11:19] GC: You want to be able to enforce what the agent can message and where it can get messages from. You've got, for example, a WhatsApp or Telegram. WhatsApp is maybe the most clear example of that. You have a WhatsApp bridge, a WhatsApp connector. If you're connecting with normal WhatsApp, not a business WhatsApp. So most people are using a package called Baileys. It kind of reverse-engineer the API that WhatsApp desktop uses, and that connects using that same API. It's a non-sanctioned, let's say, community connection to WhatsApp. That connection connects to your WhatsApp account, your WhatsApp identity. And that same connection can connect to every WhatsApp group that you're in, every contact, every message. It just downloads everything. When I started to use OpenClaw, one of the things that I noticed that made me go, "Okay, wait a second. I can't actually use this for a real use case for a business for a production use case," is I started to dig through the logs debugging something and I saw that OpenClaw was actually downloading and storing every single message from every single WhatsApp group and every contact in plain text in a file on my computer. Not just the one group that I had added it to, but every single group. Now with NanoClaw, by default, when I connect it to a group, it only stores messages from that one specific group. Any message that comes in it just ignores. So now if the agent is directly connecting with WhatsApp and sending messages directly to WhatsApp, it can message any group and it can change any kinds of configurations to get messages from any group. [0:12:58] KB: Totally. It makes 100% sense to me why this would be outside in the host outside of the container, right? You don't want to give the agent direct access to WhatsApp. The thing that I was curious about is once you're inside of the container, you've passed it through SQLite. You're past your proxy boundary, essentially. You're past your moment of control. But you mentioned there's still a separate process that is pulling the input and passing it to the agent or vice versa translating from the agent into the output. And I was curious about that inside of the proxy boundary separation. [0:13:28] GC: Yeah, that's not part of the security model. That's part of the assumption is anything within the agent's environment is the agent will be able to get access to it no matter how hard I try to prevent it. That's for better quality, better quality output from the agent and to save tokens. It's all about the tokens. For the agent to pull the database itself constantly and then have whatever comes into that database just pipe straight into the agent. You can do that. You can implement an agent loop like that, and it works. You can do that. And I've implemented these really minimal versions of clause that just do that. The agent just gets whatever data gets pushed in. But that's not very efficient. So we could take it a step further. For the schedule tasks, if I set a schedule job to run, say I want an agent to check my email and process email, send me a message on WhatsApp if an email came in from a specific thing that I'm waiting for. The agent is kind of polling. If it's got a tool, it can use to read my email. It's pulling my email inbox and checking for new messages coming in. That burns through tokens like crazy. If I'm having it pulling every 5 minutes or 10 minutes, that's going to burn through tokens. And that's actually the kind of stuff that Anthropic was banning accounts for or blocking accounts from using their subscriptions for. We went and implemented, I think it's about a month and a half or two months ago, the ability for the agent to set a script that runs before a scheduled task. So, instead of the agent waking up with a prompt that says, "Go check the inbox and see if there's new messages, and send a WhatsApp message if there are," instead there's a little script that runs. The agent writes a script. When I tell the agent, "Hey, do this for me," it's got an instruction saying, "If this is really frequent, write a script first. Have a script run." And the script runs, checks something and programmatically decides whether to wake the agent or not. And that's both for tokens and also for context windows. So we're not spanning the agent with all kinds of inputs. Messages that come in to the agent's environment, we want to wrap them in a specific way. So each message gets wrapped saying who this came from, what's the timestamp, and gets presented nicely to the agent in a way that packs immediately and nicely into this context window. [0:15:42] KB: Okay. So, I want to dig more on this. This is great. I'm loving this. So, these scripts that the agent runs or is able to schedule, I presume those run inside of the container so that they're in the free-for-all security model. I don't know. Do you have names for these two security models, like the outside and inside? [0:15:59] GC: Yeah, I call them the host, not the host process or orchestration. And the agent, it's the agent runtime. [0:16:06] KB: Okay. So, I'll use those. I think the free-for-all is a little more fun as a term, but okay. So these are running in agent runtime. Agent can write scripts. Now those get triggered based on messages, or you have it sounds like a cron or something like that. Or is the cron managed outside in the host and triggers an inbox message of some sort? [0:16:25] GC: Yeah. So the agent can schedule tasks for itself. Schedule recurring tasks. I gave an agent to my wife, and she just put her in a WhatsApp group with an agent. Said, "Hey, this is Andy. He's your personal assistant. Good luck." And I left. And in the beginning it's just questions like you would ask ChatGPT. But then she started to go like, "Wait, Andy, what can you actually do? What capabilities do you have?" And then gave her all these explanations about scheduling jobs and stuff. And then she said, "Okay. Can you tell me when a certain item goes on sale." And he was like, "Yeah." And then she came to me and was like, "Hey, Andy's going to update me when this pair of jeans is on sale." And I was like a bit skeptical, and I was like, "Is he really though, or is your agent just hallucinating?" A lot of times you can tell an agent something, be like, "Remember this." And I'll be like, "Great. Note it." And then you come back to it and you're like, "Wait, what do you do with that information?" And it's just like I'm just remembering, just noting it. Mental note. And you're like, "No. You got to write that somewhere. Put it in your memory or something." Right? I was like is he really going to, or is he just like, "Yep, I'll do that?" And then the next turn, whatever." So then I we asked Andy how are you going to notify Julia if jeans are on sale? And he said, "Yeah, I have a list of websites that sell this product, and list of product pages. And I've set for myself a recurring job every morning, 9am, to visit each of the websites using the browser that I have in my environment. And I check the price, and then I compare it to the previous prices. And then if it's on sale, I'm going to update you by sending you a message in WhatsApp." The agent schedules for itself. It has these tools of scheduling tasks, and it uses them at its own discretion to accomplish a task that the user asks it to do. The agent does that by setting - it can set its cron schedule and it can set a one-off task by just setting the time when that task should run. And then the agent actually has an MCP tool to schedule a task that the agent calls the tool. And then that process that runs inside the agent's environment sends it as a system message to the host process. And the host process writes it into the agent's inbox. The reason why the agent can't just write it to its own inbox is because it's a SQLite little database. And because we've got the host process and the agent, they're running in different processes, the SQLite DB doesn't actually sync between them necessarily. And you get conflicts. So you have to use a specific mode to read. And then you get conflicts, and you start getting all kinds of errors if they're both reading and writing from the same DB. So that's why you've got an inbox that only the host writes to and only the agent reads from. And then you've got the outbox that only the agent writes to, only the host reads from. That's why it kind of has to do this whole loop, and the agent can't write at its own inbox. [0:19:19] KB: Yeah. So to make sure I understand, for recurring tasks, the agent is essentially just scheduling a cron in its own agent runtime. But for one-off tasks, it calls an MCP that go out to the host process. The host process then writes a message to the inbox? [0:19:36] GC: The agent doesn't actually schedule a cron in its own environment. The reason is because the agent's environment isn't always up or isn't always running. [0:19:47] KB: Okay, this is another good question. Yeah. Okay, so they're both going through the same flow. Which actually I'm guessing you then use in other types of context, where essentially you have a tool that wraps around here is a deterministic way that I want to send a particular message to my host system message. Sends that. The host schedules either on a cron. Or if it's a one-off, via a message with a time stamp. Then it triggers the agent by sending it to its inbox. And then at whatever time the polling process inside the agent runtime will take, say, "Oh, it's ready," and hand it to the agent? [0:20:20] GC: That's very close. There's another detail there though that the agent container spin up and spin down based on when the agent needs to be active. So when a message comes in, I can have in one NanoClaw instance running on a machine. And actually, we stress tested this last week or two weeks ago. One machine with 16 CPUs, 64GB RAM can run about 200 containers, agent container, containers running agents running Claude SDK in parallel at the same moment concurrently. But on a smaller machine, if I only have two CPUs, 8GIG RAM, I'm only going to be able to run eight or 10 agents' containers in parallel. If I have an instance, and I have a whole bunch of different agents, because I've got different agents and different groups and different people, I don't want to have those containers running and up all the time very quickly. I run out of CPUs, run out of RAM, run out of space. The containers spin up and spin down. The persistency is in the mounted folders and in the container images. The agent can't write something in the future, for example, future cron job, in its own environment. That has to be written to the host. Now the way it's implemented just to keep everything modular and have each agent, each session managing its own things and keep the host process relatively simple, the agent calls a tool, like you said. It's a message that's sent to the host process saying this agent wants to schedule a task for this time. The host process immediately writes it to the agent's inbox but with a process after time stamp. And then the container will spin down after some period of idle. By default, 30 minutes, no messages coming out from the agent, no activity, the container spins down. And then the host process is doing this sweep over all of the agent outboxes and inboxes looking for messages that need to be processed. And when it sees a message that has its process after time stamp set for the current time, it spins up that container. And then the agent - the loop running inside the container by default, immediately when it starts up, just starts pulling the inbox, sees the message there, pushes it into the agent SDK. That's the process there. [0:22:43] KB: Awesome. Let's talk a little bit about lifecycle, right? You've already talked about how you'll spin up, spin down, you're managing persistence, it's in the mounted folder and in the inbox-outbox. Presumably, these things could be as long-lived as you want. They can be quite durable. How do you deal with things like context window compaction, those types of things for one of these agents? [0:23:05] GC: Yeah, the compaction and how we do that is we take a very simplistic approach and try to not reinvent the wheel and try to not build in a way where our code is going to be redundant with the next update of agent SDK, the next model release, the next version of Claude Code. So, we're actually just using Claude Code default compaction with just some instructions, minimal instructions, telling the agent what's important to retain in the context. And what's really important to retain is the sequence of messages going in and out from the user and the agent. Tool calls, you can draw. Actually, the content of the message can be summarized. And the instructions tell the agent to summarize the content of the message if it's long. But the sequence of messages saying the sequence, the order, who the messages are from, the timestamps, that needs to be preserved. And not necessarily all of them. You can summarize and say there's this whole beginning of the conversation that happened. And then here's the last 15 messages. And then one or two of those might be really long. Summarize the actual content of the messages, but keep the wrapper saying here was a message from the user at this time stamp. And here's a response from me at this time stamp. Compaction, we let the model, Opus, Claude, or Codex, GPT5.5, we let them handle that. And in terms of the session, it's actually just one session that keeps going by default. The session just goes on and on. And it auto compacts when it hits the limit. We set the limit a little bit below the default. Default for agent SDK is 200k at the moment. And it's kind of maybe a little bit solved with the last couple models. But the models used to get really - I think they get some kind of context anxiety when they would get close to their context window threshold or compaction threshold. They start to get kind of dumb, try to finish things really quick and take shortcuts. We set it a little bit lower and set the compaction threshold at 165K. And then by default, it just keeps going. Same session endlessly. That works quite well. When it compacts, there's a pre-compact hook that takes the full session and puts it in the agent's environment. And there are instructions in claude.md saying you've got the full context of conversations from before compactions in the conversations folder. The agent can look through previous sessions if it needs to pull in previous context. And the agent has instructions saying, "Save things." Kind of the LLM wiki model of just save things in your environment. Create files, create folders, create indexes that specify what you have in your environment, what the different files and folders have in them, and update your claude.md to reflect what are in those files and folders. And even create systems for tracking things and systems for your own memory. And then just designate what that system is. And that works quite well. The issue is that at some point the actual Claude Code session file, the JSONL file just starts to get really, really big. It can get to be 50, 100, a few hundred megabytes. And at some point it starts to break down a bit. That's something that we need to add at some point. Rotate that session and pull in some context to the new session. But actually, just compacting three sessions for that chat assistant use case, it works really well. [0:26:34] KB: Let's talk a little bit about interaction models. So you mentioned you can spin up a whole bunch of different agents. Can they talk to each other? What does that end up looking like? I know a lot of folks who are way down in this are like, "Oh yeah, I have my product manager, and my sales manager, and my this, and my that." So how does the multi-agent story work within NanoClaw? [0:26:54] GC: Yes, your agents can talk to each other. And your agents can actually create other agents. Your agent has an MCP tool, create agent. And it can give a definition, name, instructions, what that agent is supposed to look. And that creates a second agent in its own container with its own file system, its own environment, own memory. And then when your agent creates an agent, it now has in addition to destination of the Slack channel you're talking to it from. And maybe your WhatsApp group that you've connected to the same agent, it now has another destination of agent B. And agent A can send messages to agent B. And that just means it can write a message that it wraps in a little XML tag saying to agent B. And so just like it can send you a message in Slack and WhatsApp, it can send a message to agent B. That's again just a message coming out of the agent's environment. It gets put into its outbox. The host process picks that up and routes it instead of to a messaging app. It just routes it to the other agent and puts it in its inbox. And that's agent-to-agent communication within one NanoClaw instance. It's just messages in the outbox going into the other agent's inbox. And in order for me to allow agents to speak one to each other, I just need to configure them so that they have the other agent in their list of known and approved destinations. That's both for permissions and for discovery, so the agent knows who it can talk to. The other mode is just putting them in the same channel and then just having them speak to each other through whatever messaging app. So if you want to have visibility into what they're saying and you want to have a conversation where you're part of the conversation, then you just add two different agents to the same Slack channel. They talk to each other the same way you do. One thing that is missing in order to make the agent-to-agent direct communication outside of the channels really useful is an approval gate. The same way I can put an approval gate on the agents sending a message, sending an email, I really need to have the ability to have an approval gate between agents talking to each other. And a really powerful use case for agent-to-agent is having two different agents that belong to two different people. So I've got my agent, you've got your agent. And I can ask my agent a question, ask it to do something. As part of doing that task, it can reach out to your agent and ask it a question, ask it to grab some information. If we trust each other with all of our information, then we can just let that happen. Let our agents chatter behind our backs and maybe that's okay. But if you're talking to your agent about some private things that you wouldn't want to be shared with other people, so then you want to have an approval gate before your agent sends a response. And you want to see what that response is and verify that it's not sharing something that you wouldn't want being sent out. [0:29:44] KB: When you have that type of multi-person, multi-agent, and this is fascinating because we're getting into a question that everybody's grappling with now, which is multiplayer AI, does that need to be through an external channel like a Slack or something like that? Do you have a peer-to-peer model in this? How is that working? [0:29:59] GC: I think if multiple people are going to be talking to the same agent, it does make sense to have that happening in like a Slack channel. I think there's a false sense of - and this is just from like the psychology of the end user. If I'm talking to an agent in a DM, that feels like a private conversation. And if somebody else is speaking to that same agent in a DM, then that gives me a false sense of privacy because that agent could just be sharing everything I'm telling it with another person in a different DM. I think the right way to do it is if we're all speaking to the same agent, probably have that in a group and have that visible and immediately apparent to all the users so everybody's aligned that this is a public forum. And anything I share with this agent is public information. Where it gets interesting is I'm chatting with my agent. It's got all this information, very useful information that's really useful to people on my team. And the same way people on my team can come and ask me questions, and I can share with them some of that information, but not share other pieces of information that I've got in my head. You do want to have your agents, as they're building up this LLM wiki, this knowledge graph of everything they know, a Wikipedia of you and everything you know and everything you're working on. You want them to be able to share some of that information with other people and not share other parts. And that's where I think approval gates are interesting and are useful. I think the first step is an approval gate where every single message going out I see and I have to approve. And then you can start playing around with maybe classifiers. Maybe a model, a smart model. It doesn't have to necessarily be an agent. Maybe it's just an LLM call that looks at what's being shared and looks at a set of instructions, and makes a call on whether this is blatantly safe and innocent information, or if it should be routed to me to get my approval. And that's obviously going to be trading off a little bit of safety for convenience. So, you got to make sure you shouldn't be doing that with highly sensitive information and anonymous users from the public engaging with it. But if it's for someone on my team and I know that some of the information maybe isn't ideal for other people to have, but it isn't going to cause a real crisis. Maybe I'll allow an LLM to look at some of the responses and auto approve some of them. [0:32:22] KB: Interesting. Okay. Another slightly different topic. I'm an engineer. First thing I think with agents is I'm like, "Okay, I want it to build things for me." Maybe I want to use multiple agents. One that builds and one is a code review agent, or things like that. But the only inputs and outputs here are messages. How do I navigate the creation of artifacts using these agents or getting those in and out of those kind of local container agent runtimes? [0:32:47] GC: We built internally - and we'll likely open source this soon, maybe mid June or maybe recently. Not sure. But we created our own agent factory. And I know everybody's doing that. Every company that's worth its weight has got their own agent factory. Our agent factory reviews pull requests to the NanoClaw open source project. It reviews. But the most useful part of what it does is isn't actually the review. The review is somewhat useful. Maybe we'll catch some edge cases. But I think the core part of the review in an open source project is really about is this aligned with the project philosophy approach where we're going. And that is a lot of taste and judgment. And agents aren't very good at that even with instructions. They're doing the security review, code quality review. But then the agent creates a testing plan. And then the testing plan goes to a testing agent. The testing agent gets a VM that's been spun up for it with the pull request branch checked out in that VM. The testing agent SSHs into the VM, runs the NanoClaw instance of that this PR with the PR's code changes, and then actually runs it. It runs some automated tests, but it actually runs it and then starts sending messages via Telegram and reading out the responses. Doing real kind of QA testing. You would do manual testing just before you deploy something. And it does that in a real environment. Checks the results, sees - first of all, I sent it a message in Telegram. Did I get a response? What is the response? And then can actually also look through the logs and look through the DB and see that everything makes sense and is as it should be. And it can improvise. If the environment doesn't have the necessary dependencies for whatever reason, it can install them. It can add test cases. And then it writes out testing results. And then those everything gets posted. The whole process of triage, review, test plan, test results, decision at the end, it all gets written out to a channel. And then at the end, the first agent gets the test results and then has a tool where it can write a GitHub CLI command. It doesn't have credentials in its environment. It just writes the command as sort of a draft. And that command gets presented to us in the Slack channel, and then we can approve or reject. And then if we approve the command, it gets run with our credentials. If I approve it, it gets run with my credentials. If Daniel approves, it gets run with his credentials. That's us taking the action. It's not the agents just automatically merging pull requests. It's the agents going through this process. We look at the work they've done, ask some follow-up questions, do some tests ourselves, and decide to merge, or crest changes, or close, or whatever. Those artifacts - the agent is running in its environment. It writes a test plan markdown file to a specific location and then sends a message to the host saying, "I've done the test plan. This is ready for testing." The host process orchestration, non-AI process, purely deterministic, gets the agent's message and then grabs the test file. And then we'll put it in, say, the test plan. It grabs it from the review agent that writes the plan, puts it into a location in the environment of the agent that runs the tests and then sends that agent a message going, "Hey, you've got a test plan in your environment. Do something with it." [0:36:18] KB: So if I'm hearing ing you properly. Essentially, the agent is writing artifacts, whether it's a markdown file, or code, or whatever. It's writing that locally in a location. It sends a message to the host saying, "Hey, I've got this artifact here. I'd like this other agent potentially to take a look at it." And the host then either copies it or does something to pull it out of that environment and puts it over in the other agent's environment and sends it a input message saying, "Hey, you have this new stuff. Go and look at it." Is that correct? [0:36:45] GC: Yeah, that's exactly correct. Rather than having the agent write arbitrary messages to the host, we give it a tool that it calls saying send to testing. And then it calls a send to testing tool. And then the send to testing tool deterministically writes a message out to the outbox that the host gets. And the agent has to put the message in a specific location. It can't just arbitrarily write locations for the host process to read because there's all kinds of security issues with that. There's a specific location. The agent has to put the message in its environment. The artifact, the host process only grabs it from that specific location. If it's not in that location, the host returns an error message to the agent. [0:37:28] KB: Okay. Let's shift direction a little bit. I want to ask you about some of the sort of product philosophy. You mentioned judgment for where the open source project is going. And I think you've taken a few very deliberate choices in how you architect. And kind of the forking model is very interesting. Maybe give me the big overview or quick TLDR. And then we can dive into details of what is your product philosophy? What belongs in this open source project and what does not? How do you approach it? [0:38:01] GC: The product philosophy is about minimalism. There are prerequisites. It has to be secure. It's got to follow the security model. But then a key part is minimalism. Keeping it small, keeping it simple. I think this whole world, the wild west of running autonomous agents that can run bash commands and write arbitrary code, it's something that everybody should be a bit nervous about, right? For developers, for security experts, that should give you a bit of pause, right? When I sat down to write this, I said, "Okay, this is inherently something that is worrying." In order for me to be confident that when I'm adding new capabilities, new features, the project is evolving, it's staying secure. In order for other people to be confident running it, I don't think they should just assume that it's okay because it's got a bunch of stars or some other people looked at it and thought it was okay. I think people should be looking at it themselves and verifying that it's okay. In order for it to be auditable, it has to be small. Keeping it small, keeping it minimal, that's a core part of the philosophy of the project. Small and minimal though means that it doesn't have everything that everybody needs. My sort of rule of thumb is I'm only going to merge something or add something if I think it's relevant for 80% to 90% of users. If something's a bit niche, it's a very specific environment. It's a very specific use case. Even if it makes sense for that use case and it's clean, I'm likely not going to merge it. Maybe if it's really minimal, if it's only a couple lines of code and it adds something great, I'll merge it. But if it's adding hundreds of lines of code and it's something that's a bit niche, even if everything is fine, it makes sense, it adds value for certain users, I wouldn't merge that. I'm very intentionally trying to keep the code base small. So then if it's minimal, if it's small, it's got 80%, 90% of what people need. And it means that there might be a small subset, 20% of users, that it's got everything they need. And they don't need to customize it. But actually for most users, it only gets them 90% of the way there. And everybody's got to add a couple things to make it work for their use case. And I think though that that's true for any tool you use, every tool that you use. You wish there was just that one thing that worked a little bit differently or it just had that extra capability. The approach that we took with NanoClaw is customization on the code level. Changing the code is supported. We're trying to support that as a first class capability. Everybody can get exactly what they want and only what you want. You can get rid of the things you don't want. If you want it to run on Telegram on Signal and not have WhatsApp, then your fork only has Signal, it only has a code related to Signal. It doesn't have any code related to WhatsApp. It doesn't have dependencies from WhatsApp. And then if you want yours to format the messages in a different way, if you're using it purely as a coding agent and you don't want it to have messages wrapped with timestamps or some other stuff, you can change the formatter and change how messages are piped into the agent. And all of those things kind of work together. If it's really minimal and really small, then people can customize it. And we're not going to be constantly pushing out new updates and new versions that are going to break their customizations. And it can stay maintainable. What it does mean though, in order to be able to customize it in a way that upstream changes are not going to break you and you'll be able to pull them in, you have to follow a sort of modular way of coding, which is in a way kind of just coding best practices. But you do have to code in a clean way and add things in a clean way. What that means is essentially add as many files as you want. But if you're changing existing files, and you will need to, you're going to have to integrate somewhere, keep your integration points really minimal. Have one two-line integration. You import something, you call it in one place, and then all of your other customization should be in new files. And if you follow that, you're going to be pretty safe. There are going to be minimal conflicts when you're pulling in upstream changes. One thing that we haven't done a good enough job with is communicating that in the documentation, in the instructions for coding agents, communicating that to the community, to the people who are using it. There's definitely been some frustration and some challenges with people updating their versions, pulling in upstream changes when they've actually forked the repository and diverged from upstream. That's actually something that we've been working on in the last few days of just defining what is our contract with the open source community with fork maintainers, people who have their own forks. What's our responsibility towards them? And what do they have to abide by if they want to ensure that we're not going to break their fork with every new update? And what are the things - what's the surface area of the project that we can commit to? And if we do change it, we'll consider it a breaking change and will provide a clear, well-defined migration path. That's something that we're defining now. I think there's a huge advantage to this approach. Ultimately, we've got NanoClaw open source, and then we've got NanoCo, which is a company. It's our company. We raise capital. Raised $12 million. That positions us really well to continue to build and maintain NanoClaw as a free open-source MIT license project. Make sure that that's not going to kind of drop off and be abandoned. We're going to be able to continue to maintain it and build it as infrastructure that people can build on, as a free project people can use for their own personal use, as something you can use in your company, in your business, for your team. You can build services, products, platforms on top of it. As a commercial entity, we're focused on bringing agents to companies. Companies that are not building their own internal agent platform on top of NanoClaw, but they just say, "I don't want to build it myself. I don't know how to build it myself. I do know how, but I don't want to dedicate the engineering hours to building our own internal agent platform for the marketing team, for the sales team." For those companies, we're going in and helping them get set up with agents. And it means we're doing some services, FDs, creating a custom deployment for each company, and then managing and maintaining those agents over time. That means that we have a lot of forks ourselves. [0:44:39] KB: And you're incented to make that easy. [0:44:43] GC: Exactly. We will be the largest maintainer of NanoClaw forks going forward at some point. I mean, we are already and we will be in the future. So that means we have to figure that out and we have to nail it. We have to figure out how to maintain a bunch of forks and not break those forks. And we're dedicated. And that's a big focus right now, figure how to do that well, so that we can do it for ourselves, we can do it for the community. And we can have a big community around the open source project. And I think it's doable but it is a different approach. I don't know of another project that's taken this approach before. [0:45:20] KB: It's interesting to me - it is very AI-forward. It's taking this model that we have now of software is this much more moldable, everybody can change it type of thing. I saw this change play out a little bit in the front end with the rise of things like Shadcn, which is like the old model was, "Hey, you've got this library. And maybe you extend it in some ways. The new model is, "No. Just copy this component, and then make it yours. Do whatever you want." And you're kind of taking that at the whole project level here of saying, "Hey, copy this, and then make it yours." [0:45:49] GC: Yeah, I love that you said Shadcn because that to me is an analogy that I have in my mind and something that I thought about. And in some ways, is one of the inspirations for it. And I haven't heard anybody else talk about that. I mean, it's obviously super popular in the front end, but I don't know how well known it is more broadly. But yeah, it's sort of the Shadcn model. But there's a bit of a difference there, because with your component library, you create your button. There isn't that much innovation happening on the HTML. [0:46:19] KB: Yeah. You copy once and you're done. You're not going to need to do the update. So you have another layer on top of that. [0:46:25] GC: Because we're building on coding agents, and the coding agents are constantly changing multiple times a day. We have to be able to pull in changes. We have to be able to expand and improve capabilities. Even if we said NanoClaw is perfect, it's complete, which it isn't. There's a lot to add even if coding agents were static. But the coding agents aren't static. They're constantly evolving and changing. So we have to be constantly updating. It means our users have to be able to be pulling in updates. Yeah, it's a bit complicated. But the way we're doing it - and this was the thing. So Andrej Karpathy tweeted about did this big thread about claws, and he called out specifically NanoClaw and said it slightly blew his mind, which I think is the height of compliments from Andrej Karpathy. [0:47:05] KB: Yeah, you've made it now. [0:47:06] GC: Yeah. And the thing that he specifically found mind-blowing was this approach of using skills as the way to customize NanoClaw, to customize your fork. So if you add integration with Spotify, you go and modify your fork so that it connects to Spotify. So you make all these code changes, then you want to contribute it back to the project so other people can have their NanoClaw agents talk to their Spotify. The way to contribute that back, Spotify is not the kind of thing that's going to be merged into the core codebase because it isn't a capability that 80% to 90% of users need, but it's a great capability. It's really cool. It's definitely the kind of thing you want to share and other people would find useful. The way you do that is you create a skill. And this skill is not a sort of runtime skill that the agent uses to do some work for you. It's a skill that's telling the agent, "Here's how you can modify NanoClaw to connect to Spotify." [0:48:01] KB: Oh, fascinating. [0:48:02] GC: Yeah, you think of that as a skill. [0:48:03] KB: You're wrapping up essentially the code changes necessary as a prompt and maybe a set of scripts or whatever, anything that can go in a skill. And you're saying this is a modify NanoClaw to connect to Spotify skill. And it will change whatever is needed in the host process and communicate whatever is needed to the agent runtime, and make it so your NanoClaw can talk to Spotify. [0:48:25] GC: Exactly. The skill standard includes with it the concept of having scripts. But it can actually have arbitrary files. Putting TypeScript files in the skill folder and saying this is a TypeScript file that you've got to add. [0:48:40] KB: Copy this over here. Fascinating. Yeah. Yeah. Yeah. That's really interesting. [0:48:44] GC: It's almost deterministic. I just need to copy it. But then it's not quite deterministic because I do need to integrate it in some place, and that place is going to change. It's not an exact line number. [0:48:55] KB: Right. Because my NanoClaw is different than your NanoClaw. So, it's going to be - Yeah. Yeah. Yeah. No, this makes a ton of sense. [0:49:02] GC: Yeah. But we're communicating to the coding agent the intent of here's what we're trying to do. Here's how it's supposed to work. Go to this file. You'll need to import it there, and you'll need to add it somewhere within the function that handles the routing of the messages, but not an exact line number. And even the edit is not an exact edit. It might need to change it a little bit and add some parameters. And the agent will be able to figure it out and do that almost deterministically. Some skills are deterministic. All I need to do - if there's a type of skill that is needed often enough, for example, adding messaging apps. When I need to integrate with a new messaging app, those skills for the most part can be applied fully deterministically. And to do that, we just need to create a kind of barrel file that's a registry and you add an import. You've got a little registry thing. Anything that's imported into that file gets registered and is available in runtime. For skills like that, we add the extra overhead, the extra level of abstraction because it's a hot spot and it's needed. And there you've got a few files that you add. And then you've got appends. Append-only. Appending an import to a file. And then you've got maybe something that you need to add to a command you run. NPM install. I need to install some dependencies. There's no conflicts there. And that can be done basically deterministically. And then, by the way, most skills also have a certain amount of user instructions. The coding agent runs all these things, adds all the code, integrates it, runs some tests to verify that the integration works. So integration tests together with the unit tests. And then the agent is prompted to walk the user through authenticating with Spotify, getting the token. And it can guide you through - [0:50:49] KB: Yeah. Yeah. Yeah. Yeah. Yeah. That's fascinating. One more direction I want to go down. So you referenced Claude Code a lot. You also threw in a line about being able to use GPT5.5. And you've talked about the way that the agent underlying tool landscape is changing very quickly. One of the things that I immediately wonder is can I plug in whatever agent harness I want? Can I use Codex? Or recently, I've been going deep on using Pi for things. Can I swap in Pi as the core agent harness? Or how does that layer of customization work? [0:51:21] GC: Yes, we have an agent provider abstraction, and that's another place where we have that registry model where you can plug in another coding agent without having to kind of mess with existing files. Just add files, append to existing files, and then add dependencies. We have supported with Skills, Codex and OpenCode. Because the project is really small, because you've got reference implementations there of how other coding agents were added, if you point Pi at the project and say, "Add an integration for Pi here,' it will do it in five minutes and 50 whatever. A couple hundredk tokens. It's a trivial kind of addition. It's very greenfield coding. And that's I think one of the ideas behind it, that any capability you want to add, it doesn't matter if it's the 10th capability or the thousandth capability, it's always greenfield because the project stays really small, really minimal. You can add that. If you add it, you can contribute. Add Pi as a skill to the project. And there's a pull request open, and maybe we'll add it soon, to add ACP, agent client protocol, which once we merge that, it will just support basically every coding agent. But we do integrate on the level of coding agents. We don't integrate with light LLM and route API calls from Claude Codes to different LLMs. I think that isn't really working anymore. Probably hasn't worked well for a while. But as we move forward, I think it's going to work, or it's going to be worse and worse. Because the agents, the models are being trained in the harness. Being trained in Claude Code and Codex. [0:53:08] KB: If you allow OpenCode and you allow Pi, they can handle the multiplexing to whatever model you want. That's not a big deal. [0:53:15] GC: Yeah. If you want to use all kinds of models, use Pi, use OpenCode. But also, I mean, the instructions don't really transfer over. There's a whole family of models that are Claude family of models that are distillations or whatever Claude. And probably there's some compatibility between them. But when you go between Claude and Codex and Gemini, they're very different models, very different instructions, skills, tool definitions. Things don't just transfer over as well as people would like them to. [0:53:43] KB: Well, in that domain, right? I'm playing a lot. And there's a few things that NanoClaw has done that I've stolen in different plays for some of my own play. You have a lot of really interesting stuff in here. But one of the things I've been thinking about is how do you create small custom agents with self-tuned eval'd prompts for particular purposes? And sometimes you want to do different models. The thing I'm kind of wondering about is how much of the prompt of the different things, of the skills, etc., is kind of baked in to NanoClaw. How much can you customize per agent where you say - for example, let's pick one of your tools. You had a messaging tool, right? That is how you send messages. Can I have a custom messaging tool per agent because I happen to know this one's running GPT5 and this one's running Opus? And they need slightly different prompts to be able to use the tool properly? [0:54:35] GC: Not by default. But you can fork the project and make that kind of change. So changing the instructions, the tool definitions of the default tools. We have the ability - you can set for each agent instructions, skills, NPM packages, and MCP servers, and some other things. But the ability to tweak the tool definitions per agent don't have that. Maybe it's something we should add. [0:55:02] KB: You may not need to, right? It may be that everybody's running Claude models or Claude family models and they stay as the front runner. But yeah, thinking about this world of who knows which model is going to be best in a year. And as you highlight, they behave very differently. [0:55:17] GC: We are moving towards CLI tools as well. There's a whole set of tools for scheduling tasks via schedule, lists, update, delete. And we're moving towards having all of that as a CLI tool. As you start to add more and more, it just gets to a ridiculous amount of tools. And it's a big debate. But I think CLI is pretty safe. And then it starts to become less and less critical, I think, because it isn't always there in context. Even with the MCP tools now that you're using tool search. A lot of the tool definitions aren't actually in context by default. And you do have the ability to adjust your own instructions per agent. There's certain pieces of the Claude MD that are like system definitions about how to - the environment that it's in, and how to schedule things and instructions like that. Those are the kind of things you have to fork to adjust. In the end of the day, though, the harness, the orchestration, NanoClaw as orchestration, it's trying to not do too much. It isn't injecting a lot of messages. It isn't changing things. It formats the messages going in. It provides some instructions about how to use the tools. But we're building very intentionally in a way of assuming that models are going to get better, agents are going to get better. Let's leave as much as possible to the models and the agents so that we benefit from the next update. And so the next update doesn't just make weeks of engineering work become redundant. Memory system, for example. I have no doubt that Anthropic has dozens, maybe more people on making the agent memory better. That's probably at every level from tuning the instructions, to pre-training, to post-training, to everything. We're not trying to build really elaborate memory systems that are kind of deterministic and all this kind of clever engineering. It's just a set of instructions that tells the model, "Here's an idea, some guidelines about how you could save things in files and folders. And move things from files to folders, and reorganize them. And keep an index of what files and folders you have." And you can change this definition of the memory system in this actual file to make it more or less complicated. But it's your memory system to manage as you see fit. And that guarantees us that as the models get better, they're going to manage memory better. [0:57:48] KB: We're getting close to the end of our time. Is there anything we have not talked about that you think would be important to leave listeners with? [0:57:56] GC: I think one of the things I would say is, last year, I spent a lot of time building agents out of LLM calls in an agent framework. The one I was using was OpenAI's framework, which worthy is also agent's SDK. But that's where you're building agents by - you got an agent loop, and you're defining everything. And you got to deal with caching. And you got to deal with the tool definitions, and compaction, and everything. That's really hard, right? Thinking about caching is hard. Thinking about compaction is hard. Session management. There's months and months and months of work just to get yourself a basic agent that's has the core capabilities that Claude Code has, or that Codex has, or that OpenCode has. If some people out there are still in that place where they're going, "Maybe I'll use LangChain or LangGraph, and I'm going to build an agent," my advice to you is don't do that. Save yourself the work. There's so much value that can be unlocked from using Claude Code, from using Codex, using their SDKs to build all kinds of wild agents on top of that with all kinds of orchestration and workflows, using skills, using instructions, using regular good old engineering, building products and platforms on top of the existing agents. Focus on unlocking the value over there rather than re-implementing the basic element, basic building block of an agent. Look at a coding agent as a building block, and then build a product, or a platform, or something on top of that. And then in terms of I think a lot of people get stuck on which model, which agent. Don't get stuck there. Any of the frontier models are good enough, but use a frontier model when you're building. Don't try to optimize for cost. If the thing you're building for doesn't make sense, unless it's super optimized for cost, it might not be high enough value use case where it makes sense to dedicate your time building towards that. Find a use case where if you nail this, it's going to be worth spending tokens on a frontier model. And there's definitely optimization to do, but first focus on just nailing the thing, creating a lot of value, doing something that's really valuable using coding agent, using frontier model. And once you figure that out, then maybe think about the economics of it and how do you optimize a low cost. [1:00:19] KB: Seems like a good place to wrap. [END]