Policies API
Overview
Policies define what agents can and cannot do within a workspace. They cover three areas:
- Command rules: allow/deny patterns for executable commands
- Network rules: egress allowlist (which hosts the workspace can reach)
- Secret rules: which secrets are available to which workspaces
When a workspace has a policy attached, every exec call is evaluated against the policy's command rules before execution. If the command is denied, a 403 response is returned.
Create Policy
Creates a new policy with default safety rules.
curl -X POST https://api.nanoterm.dev/api/policies \
-H 'Authorization: Bearer nt_xxx' \
-H 'Content-Type: application/json' \
-d '{
"name": "coding-agent-policy",
"description": "Standard rules for coding agents",
"commandRules": [
{ "action": "deny", "pattern": "rm -rf /", "description": "Prevent root deletion" },
{ "action": "deny", "pattern": "sudo *", "description": "No privilege escalation" },
{ "action": "allow", "pattern": "npm *", "description": "Allow npm commands" },
{ "action": "allow", "pattern": "git *", "description": "Allow git commands" }
],
"networkDefault": "deny",
"networkAllowlist": [
{ "host": "registry.npmjs.org", "description": "npm packages" },
{ "host": "github.com", "description": "Git repos" }
]
}'
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | — | Policy name |
description | string | no | null | Human-readable description |
commandRules | CommandRule[] | no | default deny list | Command allow/deny rules |
networkDefault | "allow" | "deny" | no | "deny" | Default network behavior |
networkAllowlist | NetworkRule[] | no | npm/github/pypi | Allowed egress hosts |
secretRules | SecretRule[] | no | [] | Secret access rules |
CommandRule:
{ "action": "allow" | "deny", "pattern": "npm *", "description": "optional" }
NetworkRule:
{ "host": "registry.npmjs.org", "description": "optional" }
Response: 201 Created
{
"id": "pol_a1b2c3d4",
"orgId": "org_x1y2z3",
"name": "coding-agent-policy",
"description": "Standard rules for coding agents",
"commandRules": [...],
"networkDefault": "deny",
"networkAllowlist": [...],
"secretRules": [],
"createdAt": "2026-04-06T08:00:00.000Z",
"updatedAt": "2026-04-06T08:00:00.000Z"
}
Default Rules
If no commandRules are provided, these deny rules are applied automatically:
| Pattern | Description |
|---|---|
rm -rf / | Prevent root deletion |
rm -rf /* | Prevent root deletion |
mkfs * | Prevent filesystem format |
dd * | Prevent raw disk write |
sudo * | Prevent privilege escalation |
chmod 777 * | Prevent open permissions |
:(){ :|:& };: | Prevent fork bomb |
Default networkAllowlist when networkDefault is "deny":
| Host | Description |
|---|---|
registry.npmjs.org | npm packages |
*.npmjs.org | npm CDN |
github.com | Git repositories |
*.github.com | GitHub APIs |
pypi.org | Python packages |
*.pypi.org | PyPI CDN |
archive.ubuntu.com | Ubuntu packages |
List Policies
curl https://api.nanoterm.dev/api/policies \
-H 'Authorization: Bearer nt_xxx'
Response: 200 OK — Array of PolicyInfo
Get Policy
curl https://api.nanoterm.dev/api/policies/pol_a1b2c3d4 \
-H 'Authorization: Bearer nt_xxx'
Response: 200 OK — PolicyInfo
Update Policy
curl -X PUT https://api.nanoterm.dev/api/policies/pol_a1b2c3d4 \
-H 'Authorization: Bearer nt_xxx' \
-H 'Content-Type: application/json' \
-d '{
"commandRules": [
{ "action": "deny", "pattern": "rm -rf *", "description": "No recursive delete" },
{ "action": "allow", "pattern": "pytest *", "description": "Allow tests" }
]
}'
Only the provided fields are updated; others are preserved.
Response: 200 OK — Updated PolicyInfo
Delete Policy
curl -X DELETE https://api.nanoterm.dev/api/policies/pol_a1b2c3d4 \
-H 'Authorization: Bearer nt_xxx'
Response: 200 OK
{ "ok": true }
Evaluate Command
Test whether a command would be allowed or denied by a policy, without actually executing it.
curl -X POST https://api.nanoterm.dev/api/policies/pol_a1b2c3d4/evaluate \
-H 'Authorization: Bearer nt_xxx' \
-H 'Content-Type: application/json' \
-d '{"command": ["rm", "-rf", "/"]}'
Response (denied):
{
"allowed": false,
"reason": "Blocked by policy \"coding-agent-policy\": Prevent root deletion",
"matchedRule": {
"action": "deny",
"pattern": "rm -rf /",
"description": "Prevent root deletion"
}
}
Response (allowed):
{
"allowed": true
}
Attaching a Policy to a Workspace
Specify policyId when creating a workspace:
curl -X POST https://api.nanoterm.dev/api/workspaces \
-H 'Authorization: Bearer nt_xxx' \
-H 'Content-Type: application/json' \
-d '{
"name": "coding-agent",
"image": "ubuntu:22.04",
"policyId": "pol_a1b2c3d4"
}'
Once attached, every POST /api/workspaces/:id/exec call will evaluate the command against the policy. If denied, the API returns 403:
{
"error": "Command blocked by policy",
"reason": "Blocked by policy \"coding-agent-policy\": Prevent root deletion",
"stdout": "",
"stderr": "Blocked by policy \"coding-agent-policy\": Prevent root deletion",
"exitCode": 126
}
Rule Evaluation Order
- Command rules are evaluated in order (first match wins).
- If no rule matches, the command is allowed.
- Glob patterns are supported:
*matches any characters,?matches one character.
Place more specific rules before general ones. For example, allow npm test before deny npm * if you want to allow only npm test.