Docs

Outbound rules

Decide what the sandboxes on a template may reach: everything, nothing, or a list of addresses.

For your agent

agental.io/docs/outbound-rules.md

A sandbox reaches the internet unless its template says otherwise. The rule is set on a template, and every sandbox on it is held to it. A sandbox can have addresses of its own on top. The rule is enforced on the server the sandbox runs on, outside the virtual machine, so nothing running in the sandbox can change it, root included.

RuleWhat it lets out
openEverything. Every template is open until its rule is set, default included.
blockedNothing.
allowlistOnly what goes to an address in allow: IPv4 addresses and ranges, over any protocol and port.

Set a template's rule

PUT/v1/templates/{id}/network
curl -X PUT https://agental.io/v1/templates/{id}/network \
  -H "Authorization: Bearer $AGENTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"outbound":"allowlist","allow":["203.0.113.7","198.51.100.0/24"]}'
json
{
  "outbound": "allowlist",
  "allow": ["203.0.113.7", "198.51.100.0/24"]
}
  • The rule that is sent takes the place of the one the template had. An allowlist is replaced, not added to: send every address each time.
  • The answer is the rule as it is kept: a range by its first address, so 198.51.100.7/24 comes back as 198.51.100.0/24, and no address twice.
  • It raises the template's revision, as a change to its secrets does. The same rule sent again changes nothing, so the request is safe to repeat.
  • Saving it changes no sandbox that is running. Each takes it at its next start, or now when you apply the template.
  • GET /v1/templates/{id}/network reads it and changes nothing. GET /v1/templates/{id} has it as network.

Give a sandbox addresses of its own

PUT/v1/sandboxes/{id}/network
curl -X PUT https://agental.io/v1/sandboxes/{id}/network \
  -H "Authorization: Bearer $AGENTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"allow":["192.0.2.99"]}'
json
{
  "outbound": "allowlist",
  "allow": ["203.0.113.7", "198.51.100.0/24", "192.0.2.99"],
  "template": {
    "templateId": "tpl_0123456789abcdef",
    "name": "coding-agent",
    "outbound": "allowlist",
    "allow": ["203.0.113.7", "198.51.100.0/24"]
  },
  "own": { "allow": ["192.0.2.99"] }
}
  • The list that is sent takes the place of the one the sandbox had. Send {"allow":[]} to remove them all.
  • It holds from when the request answers, on a sandbox that is running or stopped. The sandbox is not restarted, and connections that are already open are not cut.
  • outbound and allow are what the sandbox is held to now. template is its template's rule as the sandbox has it, and own is its own addresses.
  • The rule is the template's. Sending outbound to a sandbox is refused with 400 rule_on_template.
  • GET /v1/sandboxes/{id}/network answers the same and changes nothing. GET /v1/sandboxes/{id} has what the sandbox is held to as network.

What a sandbox is held to

Its template's rule, with its own addresses on top. Its own add to what the template lets out, and never take any away.

Its template's ruleWhat the sandbox is held to
openopen, whatever its own addresses.
blockedAn allowlist of its own addresses, or blocked if it has none.
allowlistAn allowlist of the template's addresses and its own.

The template's addresses and a sandbox's own come to 100 at most. More is refused with 409 too_many_addresses, and nothing is changed: when the template's rule is saved, and message then names the sandbox; when a sandbox's own addresses are set; when a sandbox is made or forked; and when it is put on another template.

Make a sandbox

POST/v1/sandboxes
curl -X POST https://agental.io/v1/sandboxes \
  -H "Authorization: Bearer $AGENTAL_API_KEY" \
  -H "Idempotency-Key: fix-login-bug-1" \
  -H "Content-Type: application/json" \
  -d '{"name":"fix-login-bug","templateId":"tpl_0123456789abcdef","network":{"allow":["192.0.2.99"]}}'
  • The machine is made held to its template's rule, with its own addresses on top, so it never runs open first, not even while it boots.
  • Leave network out and it has no addresses of its own.
  • A fork is on its source's template, held to the template's rule as it is now, with a copy of its source's own addresses on top. Changing one sandbox's addresses afterwards does not change the other's.
  • A sandbox made from a snapshot is held to the rule of the template it is made on.

When a change reaches a sandbox

A sandbox has its template's rule as it was when it last started, as it has its template's variables and files. A stopped sandbox is held to the template's rule as it is at its next start. A running one is held to it now when you apply the template.

POST/v1/templates/{id}/apply
curl -X POST https://agental.io/v1/templates/{id}/apply \
  -H "Authorization: Bearer $AGENTAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
json
{
  "templateId": "tpl_0123456789abcdef",
  "revision": 4,
  "applied": ["sbx_2a9a47e50daec64a"],
  "failed": []
}
  • Each running sandbox on the template is held to its rule, with its own addresses on top, from when the request answers. Its server is told first, one sandbox at a time. Nothing is restarted, and connections that are already open are not cut.
  • A sandbox whose server does not take the rule is listed in failed, with what went wrong, and is left as it was: held to the rule it had, and not up to date. applied lists the rest.
  • Send {"sandboxIds":[…]} to apply it to those sandboxes only.
  • Put a sandbox on another template with PUT /v1/sandboxes/{id}/template, and it is held to that template's rule at once: a running one from when the request answers, a stopped one from its next start.
  • GET /v1/sandboxes/{id}/template says whether a sandbox has its template as it is now, as upToDate.

What a rule leaves alone

  • What is sent to the sandbox. Commands and files reach it as before, and so do its public URLs and SSH. A connection that was let in is answered, whatever the rule.
  • What a sandbox is held to, through a roll-back to a snapshot, archiving and a move to another server. Only a change of its own addresses, its next start, apply, and putting it on another template change it.
  • What no sandbox reaches, whatever its rule: another sandbox, a private network, and mail delivery on port 25. An address in allow that lies inside a private network is refused for that reason.

What it does not do

  • It takes addresses, not names. "api.example.com" in allow is refused. Look the name up and list its addresses, and remember that a service behind a content network changes them.
  • Names still resolve under any rule. A blocked sandbox opens no connection, and a program in it can still ask for names, which is a narrow way for data to leave.
  • It keeps no record of what a rule refused.
  • Any key to the account can change a template's rule and a sandbox's own addresses. Do not give a sandbox that is held to a rule one of the account's keys.
  • IPv4 only. Sandboxes have no IPv6.
TipPackages, images and repositories come from the internet. Install what the work needs in a sandbox on an open template, take a snapshot of it, and have the blocked template start from that snapshot. Or list the addresses the work needs.

Errors

AnswerMeaning
400 invalid_network_policyWhat was sent cannot be a rule or an address. message says which entry and why: a name, an IPv6 address, a private range, allow without allowlist, an allowlist with nothing in it, or more than 100 addresses.
400 rule_on_templateoutbound was sent to a sandbox. Set the rule on its template, with PUT /v1/templates/{id}/network, and send a sandbox only allow.
409 too_many_addressesA list of 100 or fewer that, with the template's addresses, would come to more than 100. message says how many of each. Nothing was changed.
409 template_changedThe template's rule changed three times while a sandbox's server was being told it, when the sandbox was put on the template. Nothing was changed: send it again.
409 sandbox_archivedThe sandbox's disk is in storage. Start it, wait until it is running, and send its addresses again.
409 sandbox_migratingThe sandbox is being moved to another server. Wait a minute and send its addresses again.
500 host_errorThe server the sandbox is on did not take the rule. The sandbox is held to the rule it had, with the addresses it had.

The full machine-readable reference is OpenAPI 3.1. Every page as Markdown, for an agent: llms.txt. Questions: [email protected]