Skip to main content

Workflows & Rules

This reference is for operators who define which outbound requests AI agents may make through the HTTP Egress Proxy. It covers how API workflows, domains, and rules fit together, what each rule matches and grants, and when human approval applies.

An API workflow is a named unit of egress access: the domains an agent may reach and the rules for each domain. Every agent token is bound to exactly one workflow, so an agent can make only the outbound calls its workflow allows.

The proxy denies by default. If a request does not match a domain and a rule in the token's workflow, the proxy denies it before injecting any credential or connecting to the destination. You grant access by adding domains and rules to a workflow.

On this page, the proxy is the HTTP Egress Proxy, the component that matches and decides each outbound request. The gateway is the Permit MCP Gateway that hosts the proxy and stores the workflows, the host settings, and the credentials. The gateway governs an agent's Model Context Protocol (MCP) tool calls; the proxy governs the agent's other outbound HTTP and HTTPS traffic. Trust level is always one of low, medium, or high.

API workflow and agent workflow context are different objects

An API workflow is an egress policy object that holds domains and rules. The agent workflow context in Advanced features is a separate concept that describes the operational frame an agent acts in. On this page, "workflow" means API workflow.

Workflows are dashboard objects

The asg CLI has no command to create or edit a workflow. The CLI enables the proxy, stores credentials, and mints workflow-bound tokens. See Create and edit workflows.

How a workflow is structured

A workflow has three levels: workflow, domain, and rule.

Workflow "ship_pr"
├── Domain *.github.com
│ ├── Rule open_tunnel ALL, no path → low trust # authorizes the HTTPS tunnel
│ ├── Rule read_repo GET/HEAD → low trust # applies on intercept
│ └── Rule push_commit POST/PUT → medium trust (injects credential "github")
└── Domain api.slack.com
├── Rule open_tunnel ALL, no path → medium trust # authorizes the HTTPS tunnel
└── Rule post_message POST → medium trust (injects credential "slack")
LevelDescription
WorkflowThe top-level unit an agent token binds to. It has a name, for example Ship a PR, and a slug, for example ship_pr.
DomainA host name or glob the workflow allows, for example api.stripe.com or *.github.com. The proxy denies a request whose target host matches none of the workflow's domains.
RuleInside a domain, a rule defines which requests to that domain are allowed and the trust level each requires. Each domain you reach over HTTPS also needs one tunnel rule. See HTTPS needs a tunnel rule.

HTTPS needs a tunnel rule

An HTTPS request reaches the proxy as a CONNECT request. The proxy authorizes the tunnel before the path and method inside it are visible. A CONNECT request can therefore match only a rule with method class all and no path pattern. A path-scoped or method-scoped rule never authorizes an HTTPS connection.

Every domain you reach over HTTPS needs at least one rule with method class all and no path. This page calls that rule the tunnel rule. Without a tunnel rule, the proxy denies every HTTPS request to the domain with rule_not_matched, even if the domain has read or write rules.

  • In passthrough mode, the default, the tunnel rule is the only check on HTTPS. The encrypted traffic is opaque to the proxy, so path and method rules do not apply inside the tunnel.
  • In intercept mode, the tunnel rule authorizes the connection, and the proxy matches each decrypted request against the domain's path-scoped and method-scoped rules.

Plain HTTP requests are matched on host, path, and method directly and need no tunnel rule.

What a rule matches

A rule matches a request on these fields:

FieldRequiredAccepted valuesDefaultExample
PathOptionalA glob over the request path, up to 512 characters. Must be blank on a tunnel rule.Blank, which matches every path on the domain/v1/customers*
MethodRequiredOne or more of the method classes read, write, delete, allNone. A rule with no method class is rejected with "Select at least one HTTP method class"read, write
ProtocolOptionalhttp, websocket, anyhttphttp

Method classes group HTTP methods by risk, so you do not list each method:

Method classHTTP methods
readGET, HEAD, OPTIONS
writePOST, PUT, PATCH
deleteDELETE
allAny method, including methods no other class covers, such as TRACE. A CONNECT tunnel needs all.

A rule can select several method classes.

Path globs

A trailing * matches within a path segment. /v1/customers* matches /v1/customers and /v1/customers/cus_123. /v1/customers/* requires a trailing slash and does not match /v1/customers. Leave the path blank to match every path on the domain.

What a rule grants

Rules only allow. A matching request is authorized when the caller's trust level is at least the rule's required trust level. Rules have no block or require-approval action. You control access by choosing which domains and rules exist and which trust level each rule requires.

Each rule has these settings:

SettingPurpose
Required trustThe minimum trust level the caller must hold for the rule to authorize a request: low, medium, or high. The rule declares the level. The method does not. Auto sets the level from the method class (readlow, writemedium, delete and allhigh). You can set a higher or lower level instead.
CredentialOptional. A stored credential to inject into matching requests, so the agent never holds the secret. On an HTTPS domain, the proxy injects the credential only on rules evaluated in intercept mode.
TLS modeFor HTTPS: passthrough (domain-level control only) or intercept (decrypt and apply path and method rules). The proxy reads TLS mode from the tunnel rule. See HTTPS interception.

Because each rule sets its own required trust level, one workflow can give an agent broad read access and require a higher trust level for writes and deletes, a level that only a person's consent supplies. See Authorization and trust.

Two requests against one workflow

Take the ship_pr workflow above, with the *.github.com tunnel rule set to intercept so the proxy matches the path and method inside the tunnel. In intercept mode the client trusts the host's certificate authority, which is why both requests below pass its certificate with --cacert. See HTTPS interception.

Both requests run in a shell where eval "$(asg proxy env <host>)" has set HTTPS_PROXY and AGENT_SECURITY_PROXY_TOKEN_FILE, so curl sends them through the proxy and reads the token from that file. See Point your agent at the proxy.

A GET to api.github.com matches the read_repo rule, which requires low trust and injects no credential:

curl -i --cacert ./agent-security-ca.pem \
--proxy-header "Proxy-Authorization: Bearer $(cat "$AGENT_SECURITY_PROXY_TOKEN_FILE")" \
https://api.github.com/repos/acme/app

Expected result: GitHub's own response for that path, forwarded by the proxy.

A DELETE to the same host matches no rule, because the domain has rules for all (the tunnel), read, and write only:

curl -i --cacert ./agent-security-ca.pem \
--proxy-header "Proxy-Authorization: Bearer $(cat "$AGENT_SECURITY_PROXY_TOKEN_FILE")" \
-X DELETE https://api.github.com/repos/acme/app

Expected result: the proxy denies the request and never connects to GitHub:

HTTP/1.1 403 Forbidden
Content-Type: application/json
X-Agent-Security-Error: rule_not_matched
X-Agent-Security-Fix: Review the rules of workflow 'ship_pr' and add one covering this request.

{"error":"rule_not_matched","message":"No rule in API workflow 'ship_pr' allows this method + path on domain 'api.github.com'. The proxy denies any request no rule explicitly allows.","fix":"Review the rules of workflow 'ship_pr' and add one covering this request."}

Every denied request carries a stable code in the error field of the JSON body and in the X-Agent-Security-Error header, so you can tell which check denied the request:

error codeWhat it means
workflow_not_foundThe token's workflow slug no longer exists in the host.
domain_not_allowedThe destination host matches no domain in the workflow.
rule_not_matchedThe domain is allowed, but no rule covers this path, method, and protocol.
permit_deniedA rule matched, and the Permit.io policy denied the agent for that rule.
consent_revokedThe person who authorized the agent revoked access and denied tokens already in flight.

Create and edit workflows

Workflows live in the dashboard under CLIs / APIs → Workflows, where you name the workflow, add its domains, and add the rules for each domain. For the click-by-click steps, see Create an API workflow.

Two ordering facts matter when you add rules:

  • Add the tunnel rule for each HTTPS domain before any other rule for that domain, because the tunnel rule authorizes the connection and carries the domain's TLS mode. A plain HTTP domain needs no tunnel rule.
  • Attach a credential to the rule that the proxy evaluates for the request you want the secret on. On a passthrough HTTPS domain, that is the tunnel rule, and the proxy injects nothing until the domain uses intercept.

An agent reaches a workflow only through a token bound to it: mint one with asg proxy token create --workflow <slug>, or have a person delegate access with asg proxy authorize --workflow <slug>.

Start with the narrowest workflow

Start with the exact domains and paths your agents need, at the lowest trust that works, and let deny-by-default block everything else. Add domains and rules when real traffic needs them. Removing access an agent already depends on is harder than adding access later.

Human-in-the-loop on egress

The proxy can pause an egress request and ask a person to approve it before forwarding it. It uses the same human-in-the-loop approvals as MCP tool calls.

The intent guardian is the host setting that triggers those approvals on egress. It scores each request against the workflow's declared intent with a language model and returns one of three verdicts: allow, deny, or step up. A deny verdict returns 403 with the guardian_denied error code. A step-up verdict is what routes the request to human approval. In the host's settings, the toggle is Enable Guardian Agent (LLM Intent Evaluator).

Human approval on egress applies under these conditions:

  • Trigger. The intent guardian's step-up verdict on the request triggers approval. A rule setting or a risk score does not. Rules have no approval action.
  • Host settings. The host must have Require Agent Identity on, because the guardian evaluates the intent the agent registered, and the guardian toggle on. Both default to off. For agent identity, see Agent identity and drift protection.
  • Traffic. Approval applies to plain HTTP and to HTTPS on rules evaluated in intercept mode. The proxy never routes traffic inside a passthrough tunnel for approval, because that traffic is opaque to the proxy.

When a request requires approval, the proxy holds the request and notifies your reviewers by email or Slack. The proxy forwards the request only if a reviewer approves it. Otherwise, the proxy denies it.

The denied request carries the outcome as an error code. The proxy returns approval_denied, approval_timeout, or approval_unavailable in the JSON body and the X-Agent-Security-Error header. When the asg CLI drives the request, it writes the upper-case form of the same code to stderr with --json, so automation can tell the outcomes apart:

CLI codeMeaningExit code
APPROVAL_DENIEDA reviewer rejected the request. Nothing was forwarded.1
APPROVAL_TIMEOUTNo reviewer responded before the approval timeout. Running the command again opens a new approval.2
APPROVAL_UNAVAILABLEThe approval round trip could not run, for example because the host is at its pending-approval limit. Nothing was forwarded.1

Next steps