Content

A 9MB agent on a $5 VPS, with rules on every API call

Picobot fits a capable agent in one 9MB Go binary. Here's how to connect it to Swytchcode so reads run and writes wait for your approval. It also explains why Picobot should run in Docker: run directly on your machine, its exec tool could reach Swytchcode's files.

Picobot has a tool called exec, and its description says it's "restricted for safety". It won't take an absolute path. It won't take ~. It won't take ...

We wanted to know if that was enough to keep it away from Swytchcode's rules file. So we set Picobot 0.3.0 up the way a native install runs, with a Swytchcode project in the same home folder, and had it try to edit the rules.

On a copy of the file, it got through three different ways.

Three ways past "restricted"

The catch is that exec runs commands from the folder Picobot was started in. It checks the arguments, not where they lead.

  1. A relative path. sed -i ... agent-swy/.swytchcode/integrations/policies.json has no /, no ~ and no ... It passed the check, and renamed the approval rule.
  2. A shell. bash -c "cd; ..." changes folder inside the command, where the check doesn't look. Same result.
  3. A wrapper. We added bash, sh and sed to Picobot's deny list. Then env sed ... did it anyway. The deny list checks only the first word of a command.

And there's no switch to turn exec off.

To be fair to Picobot, none of this is news to its maintainers: both gaps are already open as #42 and #43. And it matters for any guardrail, not just ours. Swytchcode's tools can't remove a rule, and they never did here. The agent went around them, through the shell, to the file.

Same agent, in a box

Then we ran the same Picobot in its own Docker image, with Swytchcode on the host and reached over HTTP.

The three tricks still work. There's just nothing for them to find. The rules file and the saved keys are on the host, outside the container. Inside, exec can rename whatever it likes.

All seven of our checks passed:

  • Picobot registered the 11 Swytchcode tools, as mcp_swytchcode_swytchcode_*, and the skill went into its prompt.
  • A Stripe balance lookup ran. A write stopped before it reached the API, waiting for a person.
  • A pasted key was refused. The agent got a terminal command for you instead.
  • Asked to add an "allow" rule or replace the approval rule, it was refused, and the rules file was unchanged.

The agent can read its Swytchcode token in its own config. That only unlocks the same 11 tools, so it gains nothing.

We used a mocked Stripe and a scripted model, so a real model, the chat channels and a real approval are still to test.

Why a 9MB agent is worth it

None of this is a reason to skip Picobot. It does what the big agents do (memory, tools, skills, MCP) in a fraction of the space:

BinaryAbout 9MB, one Go file
Memory when idleAbout 10MB
Docker imageAbout 29MB, Alpine
Runs onA $5 VPS, a Raspberry Pi, an old Android phone through Termux
ChatTelegram, Discord, Slack, WhatsApp, or the terminal
ModelsAnything OpenAI-compatible, including OpenRouter and local servers

The Docker image is tiny too, so running it in a container costs you almost nothing. That's the setup we'd recommend anyway.

Set it up in Docker

On the Picobot host, with Picobot's data in ./picobot-data and a Swytchcode account (approvals need the Business or Enterprise plan):

npm install -g swytchcode
swy init --operator --editor=none --project ~/agent-swy
swy login
swy mcp serve --profile operator --project ~/agent-swy --transport http -d
swy mcp token

Add the server to picobot-data/config.json, with the token:

"mcpServers": {
  "swytchcode": {
    "url": "http://host.docker.internal:5476/mcp",
    "headers": { "Authorization": "Bearer <token>" }
  }
}

Copy in the skill and restart. Picobot connects to MCP servers only when it starts:

cp -R ~/agent-swy/agent-skill/swytchcode-operator picobot-data/workspace/skills/
docker restart picobot

On a Linux VPS, the server listens on Docker's bridge and the container needs one extra flag. The Picobot setup guide has both, plus connecting your first app.

Small agent, real money

Restricted for safety is a promise about arguments. A container is a promise about what exists. Only one of them held up.

Run Picobot in Docker, keep Swytchcode on the host, and the agent can be as tiny and as clever as it likes. The refund still waits for you.

More content