Skip to content

Policies#

A policy is what an agent is allowed to do. It is a YAML or JSON document, created and updated like any other resource, and it is the single place the answer lives.

Default posture is deny. A sandbox with no policy can execute code and reach nothing.


Create a policy#

# agent-base.yaml
name: agent-base
description: Baseline egress and inference for production agents

networkDefaultVerdict: deny
networkDefaultTransport: upstream

allowedDomains:
  - pattern: api.github.com
    verdict: allow
    transport: upstream
    scheme: https
    description: GitHub API
  - pattern: registry.npmjs.org
    verdict: allow
    transport: direct
    description: Package downloads

credentials:
  - credentialName: github-token
    envVarKey: GITHUB_TOKEN

managedInference:
  enabled: true
  provider: bedrock
curl -fsS -X POST \
  -H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
  -H "Content-Type: application/json" \
  https://agents.example.com/v1/projects/$PROJECT_ID/policies \
  -d @agent-base.json
Create a policy called agent-base in the production project.
Deny by default. Allow api.github.com over upstream transport and
registry.npmjs.org direct. Attach the github-token credential as
GITHUB_TOKEN, and enable managed inference on bedrock.
nexusctl policy create --project production -f agent-base.yaml

-f - reads from stdin, which is what makes the edit loop work:

nexusctl policy get agent-base -o yaml > policy.yaml
$EDITOR policy.yaml
nexusctl policy update agent-base -f policy.yaml

Update replaces top-level fields

Each top-level field you supply replaces the existing value. allowedDomains is list-replace, not list-merge. Fields you omit are left alone, so the get-edit-update loop round-trips cleanly. Pass an explicit allowedDomains: [] to clear a list.


The policy document#

Field Purpose
name Required. Unique within its scope.
description Free text.
networkDefaultVerdict allow or deny for unmatched domains. Use deny.
networkDefaultTransport upstream or direct for unmatched domains when the default verdict allows.
allowedDomains Ordered domain rules. First match wins.
credentials Credentials to attach, by name.
connectors Connector grants with explicit tool allowlists.
integrations Clusters and AWS connections to enable.
managedInference Opt in to platform-proxied model access.
piiMasking PII masking for model calls.
env Environment variables for sandboxes using this policy.

Domain rules#

allowedDomains:
  - pattern: "*.internal.example.com"
    verdict: allow
    transport: upstream
    scheme: https
    rules:
      - method: GET
        path: /v1/reports/*
      - method: POST
        path: /v1/reports/export

Wildcards are supported in pattern. rules narrow a domain to specific methods and path globs, which is how you express read-only access to an API rather than approximate it.

transport: upstream routes the call through the platform so credentials can be injected and the request fully audited. transport: direct allows it without interception — appropriate for high-volume, low-risk traffic such as package registries.

Connectors#

connectors:
  - connectorId: 123e4567-e89b-12d3-a456-426614174000
    allowedTools:
      - jira__search_issues
      - jira__get_issue
    credentialId: 223e4567-e89b-12d3-a456-426614174000

allowedTools is required and has no wildcard. An empty array denies every tool in that reference. Tools an upstream adds later are not granted until you name them.

Integrations#

integrations:
  - type: kubernetes
    name: prod-eu
  - type: aws-connection
    name: production-aws

PII masking#

piiMasking:
  types: [EMAIL, PHONE, CREDIT_CARD, PERSON]
  unmaskResponses: true
  failOpen: false

failOpen: false is the default and the compliance-safe choice: if masking fails, the request does not go out. See Privacy and PII controls for the full type list.


Scope and resolution#

Policies live at two levels.

Scope Created with Role
Organization --org Reusable across projects, and a ceiling on what projects may grant.
Project --project Specific to one project's work.

An agent's effective policy is the merge of every policy that reaches it, clipped by the org ceiling. A project binding that grants more than the org policy permits is clipped, not honoured.

Find those cases before they surprise someone:

nexusctl policy-binding list-drift --org acme

Read what actually applies to a running sandbox:

curl -fsS -H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
  https://agents.example.com/v1/projects/$PROJECT_ID/sandboxes/$SANDBOX_ID/effective-policy

Reaching agents#

Policies do not apply themselves.

  • Sandboxes attach policies directly — they are their own principal, so there is nothing to bind. See Sandboxes.
  • Users and API tokens get policies through a policy binding.

Inspecting#

curl -fsS -H "Authorization: Bearer $LENS_AGENTS_TOKEN" \
  https://agents.example.com/v1/projects/$PROJECT_ID/policies
What does the agent-base policy in production actually permit?
Which sandboxes and bindings use it?
nexusctl policy list --project production
nexusctl policy describe agent-base --project production

describe renders allowed domains, connectors, credentials, integrations, PII masking, and current bindings as one view — the fastest way to answer "what does this policy actually permit".


Starting policy set#

Policy Scope Contents
org-ceiling Org Everything the organization permits at all. Deny by default; no credentials.
agent-base Org Managed inference, package registries, documentation sites.
<system>-readonly Project One system, GET only, with its credential.
<system>-write Project The same system with write methods, bound to fewer subjects.

Splitting read from write as separate policies makes a privilege grant a visible, reviewable change rather than a line edit inside a larger document.