Skip to main content

Overview

Teams may require human review before pull requests updated by cloud agents are merged. Run the Formal Endpoint inside each agent to enforce this workflow by preventing auto-merge from being enabled. Cloud agent platforms mint short-lived OIDC tokens for their agents. The Endpoint exchanges these tokens for a Formal machine session and refreshes them automatically. Its transparent proxy evaluates each GitHub request against Formal policy. This guide covers Cursor Cloud Agents and Devin. The general setup is the same for both. Setup steps that differ are split into provider tabs.

Prerequisites

  • A Cursor Cloud Agent environment or a Devin environment
  • A Formal machine user for your cloud agents
  • Permission to create OIDC integrations, Permissions, and policies in Formal
  • Permission to edit the cloud agent environment

Configure the OIDC integration

Go to OIDC Integrations and click Create Integration. Select your provider’s preset, then select the machine user created for your cloud agents.
1

Restrict the claim condition

Replace your-team-id in the Cursor preset claim condition. You can also restrict the integration to one repository:
Use claims.repo_urls when the environment checks out multiple repositories. See Cursor’s OIDC claim reference for all available claims.
2

Map the Cursor owner

Keep the preset End-User Email Expression:
This maps each agent action to the Formal human with the same email. Confirm every Cursor owner has a matching Formal user before activation.
3

Copy the integration ID

Copy the generated integrationoidc_... value. The Endpoint requests the audience oidc.formal.ai/<INTEGRATION_ID>.

Restrict Control Plane access

The cloud agent machine user only needs the Endpoint authentication and logging flows. Create a Control Plane Permission that denies every other Formal API and console operation for that identity.
1

Copy the machine user ID

Open the machine user selected by the OIDC integration and copy its user_... ID.
2

Create the Permission

Go to Permissions and click Create Permission. Name it block-cloud-agent-control-plane and paste:
Replace <CLOUD_AGENT_MACHINE_USER_ID> with the copied ID.
3

Activate and verify

Set the Permission to Active. An API request authenticated as the cloud agent machine user should return HTTP 403 for Control Plane operations. The Formal Endpoint can still authenticate and send logs through its dedicated APIs.

Create the network rule

The Endpoint passes a connection through untouched unless a network rule matches it. Create a rule for GitHub so the Endpoint terminates TLS and evaluates policy. Restrict the rule to your agent machine users.
  1. Navigate to Network Rules
  2. Create a rule named github-cloud-agents
  3. Match hostname github.com and api.github.com on the pre-TLS condition
  4. Restrict the rule to your cloud agent machine users
  5. Leave Forward to Connector unset
  6. Save the rule and set it to Active
Interception happens on the Endpoint. This rule does not need a Formal , Connector listener, or Forward to Connector.

Configure the agent environment

Install the Endpoint while the environment image is built. If the environment restricts egress, allow api.joinformal.com, static-assets.formalcloud.net, and each governed destination.
Cursor environment builds preserve installed files, but not running processes. Start the Endpoint again for every Cloud Agent run. The Cursor OIDC socket is local and does not require outbound access.
1

Open the environment

Open Cloud AgentsEnvironments in Cursor. Create an environment or edit the environment used by your repository.
2

Start guided setup

Start Cursor’s environment setup flow. Give the setup agent these instructions:
Replace <INTEGRATION_ID> before submitting the instructions. Use the arm64 package on an ARM environment.
3

Activate the build

Review the generated install and start configuration. Create a successful environment build, then make it active.
Use the following repository-managed configuration when you want setup changes reviewed and versioned with the repository.
1

Create the install script

Add .cursor/install-formal-endpoint.sh:
Replace <INTEGRATION_ID> with the copied integration ID. Pin a versioned Endpoint package URL when your rollout process requires deterministic versions.
2

Create the runtime script

Add .cursor/start-formal-endpoint.sh:
Cursor sets CURSOR_AGENT_SOCKET to /run/cursor/api.sock on managed Cloud Agent VMs. Do not hard-code this path because self-hosted workers use a different path. The retry handles the brief period before Cursor creates the socket during boot.
3

Make the scripts executable

4

Update the environment configuration

Add the install command and named terminal to .cursor/environment.json. Merge these fields into any existing environment configuration:
Commit all three files. New Cloud Agents use the repository-managed environment configuration.

Verify the setup

Start a new cloud agent session, then run:
formal auth whoami should show the configured machine user. The transparent proxy status should be enabled. The verbose curl output should show:
GitHub’s own certificate means the network rule is not matching. The package watches for regenerated Endpoint certificates and updates the system trust store. Run formal ca trust again if a client reports an untrusted Formal CA.

Create the merge policy

GitHub merges pull requests through a GraphQL mutation or a REST endpoint. This policy parses the GraphQL request and blocks both paths:
Create the policy in Draft or Dry-run first. Set it to Active after reviewing the matching requests.

Verify merging is blocked

Use a disposable pull request that does not already have auto-merge enabled:
The command should return HTTP 403 with a Formal policy, session, and request ID. Open Logs and confirm the blocked request contains enablePullRequestAutoMerge. The REST merge endpoint should be blocked as well:

Troubleshooting

Start the Endpoint from the environment’s runtime command or terminals, not install. Install processes do not survive an environment build. Retry with a new Cloud Agent if the socket remains unavailable.
Confirm lingering is enabled with loginctl show-user "$(id -un)". Confirm devin-oidc is on the service’s PATH. Read failures with journalctl --user -u formal.service.
Confirm the integration is active. Its issuer should be https://api.cursor.com for Cursor and https://app.devin.ai for Devin. Verify every claim in the claim condition exists on the token. Confirm the configured integration ID has no oidc.formal.ai/ prefix.
Run:
Then retry the request. Do not disable TLS verification.
Confirm the policy is Active and the transparent proxy is enabled. Confirm the GitHub network rule is Active and matches the agent’s machine user. Without a matching rule the Endpoint forwards the connection without inspecting it.

Next steps

Formal Endpoint

Review Endpoint authentication and connection options

OIDC Integrations

Configure claims and federated access

Policy Evaluation

Explore HTTP and agent policy inputs

Endpoint Logs

Review requests and policy decisions