diff --git a/src/components/Navigation.jsx b/src/components/Navigation.jsx
index 6af3ba05..68f55ca1 100644
--- a/src/components/Navigation.jsx
+++ b/src/components/Navigation.jsx
@@ -230,6 +230,9 @@ export const navigation = [
{ title: 'Install', href: '/cli/install' },
{ title: 'Quickstart', href: '/cli/usage' },
{ title: 'Commands', href: '/cli/commands' },
+ { title: 'Phase AI', href: '/cli/ai' },
+ { title: 'Phase AI relay', href: '/cli/ai/relay' },
+ { title: 'Phase AI control API', href: '/cli/ai/control-api' },
],
},
{
diff --git a/src/pages/cli/ai/control-api.mdx b/src/pages/cli/ai/control-api.mdx
new file mode 100644
index 00000000..c7d03c98
--- /dev/null
+++ b/src/pages/cli/ai/control-api.mdx
@@ -0,0 +1,624 @@
+import { Tag } from '@/components/Tag'
+import { DocActions } from '@/components/DocActions'
+
+export const metadata = {
+ title: 'Phase AI control API',
+ description:
+ 'Reference for the local phase.invalid control API that the Phase AI proxy serves to Agents running in a Phase AI session.',
+}
+
+CLI
+
+# Phase AI control API
+
+The Phase AI proxy serves a small HTTP API at the reserved host `http://phase.invalid`. Agents running behind the proxy use it to see which Connections they can use, discover what Phase can manage, and ask a human for a new or updated Integration credential. {{ className: 'lead' }}
+
+
+This is not the [Phase public API](/public-api). It is served locally by the CLI's Phase AI proxy (`phase ai run`, `phase ai exec`, the background proxy that `phase ai enable` sets up, or a [relay](/cli/ai/relay)), only to processes running inside a Phase AI session. It is not reachable from anywhere else, and it does not accept Phase tokens.
+
+
+
+
+## Reaching the API
+
+`phase.invalid` never resolves in DNS. A request only reaches the API through the Phase AI proxy, which answers it itself before any upstream connection is made.
+
+Inside a Phase AI session the proxy settings are already in the environment (`HTTP_PROXY` and `HTTPS_PROXY`), so any HTTP client that honours them works:
+
+```bash
+curl --fail --silent --show-error http://phase.invalid/v1/status
+```
+
+| | |
+| --- | --- |
+| Base URL | `http://phase.invalid` (plain `http`; the proxy answers it locally) |
+| Authentication | `Proxy-Authorization: Basic base64("phase:")`. The capability is the per-process proxy password in the session's proxy URL. It is never a Phase token. |
+| Connection scope | The proxy username `phase.` instead of `phase` scopes a request to one Connection. |
+| Format | JSON request and response bodies. Every response is sent with `Cache-Control: no-store`. |
+| Query strings | Rejected with `400 invalid_control_query`, except `wait` on request creation and polling, and `serviceType` on context. |
+| Browsers | A `POST` that carries `Origin`, `Referer`, or a `Sec-Fetch-Site` header other than `none` is refused with `403 browser_control_mutation_rejected`. |
+| Limits | Request bodies up to 64 KiB. IDs match `^[A-Za-z0-9._-]{1,128}$`. `markdown` up to 16 KiB. `wait` is 0 to 300 whole seconds. Unknown JSON fields are rejected. |
+
+A missing or wrong capability is refused before any route runs:
+
+```text
+HTTP/1.1 407 Proxy Authentication Required
+Proxy-Authenticate: Basic realm="Phase Agent session"
+X-Phase-Error-Code: invalid_runtime_capability
+Content-Type: application/json
+
+{"error":{"code":"invalid_runtime_capability","message":"A valid Phase AI runtime capability is required.","retryable":false,"details":{}}}
+```
+
+### Local proxy and relay
+
+A [relay](/cli/ai/relay) serves the same API over its TLS proxy, with these differences:
+
+| Route | Local proxy | Relay |
+| --- | --- | --- |
+| `GET /v1/bootstrap` | Not available | Available |
+| `GET /v1/discover` | Available | Not available |
+| `POST /v1/rotate` | Available | Not available |
+| `POST /v1/revoke` | Available | Not available |
+
+Every other route is available on both. An unknown or unavailable route returns `404 control_route_not_found`.
+
+## Errors
+
+Every error uses the same envelope and also sets the `X-Phase-Error-Code` header:
+
+```json
+{
+ "error": {
+ "code": "invalid_control_request",
+ "message": "Use setup with serviceType or credential_update with connectionId and credentialId. credentialProvider, credentialName, markdown, and an optional dedupKey are required.",
+ "retryable": false,
+ "details": {}
+ }
+}
+```
+
+When Phase Console rejects a call, the proxy passes Console's status, code and message through. If Console can't be reached, the proxy returns `502 agent_control_relay_failed` with `retryable: true`.
+
+| Code | Status | Meaning |
+| --- | --- | --- |
+| `invalid_runtime_capability` | 407 | The proxy capability is missing or wrong. |
+| `invalid_control_query` | 400 | The route does not accept a query string. |
+| `invalid_control_wait` | 400 | `wait` is not a whole number from 0 to 300. |
+| `invalid_control_request` | 400 | The request body is not a valid request. |
+| `invalid_control_content_type` | 415 | The body is not `application/json`. |
+| `browser_control_mutation_rejected` | 403 | A browser sent the `POST`. |
+| `control_route_not_found` | 404 | No such route on this proxy. |
+| `agent_session_unavailable` | 503 | The session is refreshing or unavailable. Retry shortly. |
+| `agent_control_relay_failed` | 502 | Phase Console could not complete the call. Retryable. |
+| `approved_request_refresh_failed` | 502 | A request was approved, but the proxy could not apply the new configuration safely. Wait until status shows the Connection as `ready`. |
+
+---
+
+## Get status {{ tag: 'GET', label: '/v1/status' }}
+
+
+
+
+ A summary of the current Workflow session: every Connection this session can use, with its Integration credential and state. It contains no credential, decoy or proxy material and is safe to print.
+
+ Check status first. If it lists a `ready` Connection for the service you need, use it; nothing else needs to be fetched.
+
+ ### Connection properties
+
+
+
+ The Connection ID. Pass it to `phase ai exec --connection` when a service has several Connections.
+
+
+ The Connection's name.
+
+
+ The Integration credential behind the Connection.
+
+
+ The Integration credential's name.
+
+
+ The credential provider, for example `aws`, `aws_assume_role` or `postgres`.
+
+
+ The credential's current revision.
+
+
+ The service the Connection is for.
+
+
+ `http` or `postgres`.
+
+
+ `ready`, `expired` (the credential's expiry has passed) or `unavailable`.
+
+
+ When the credential expires, if it does.
+
+
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl http://phase.invalid/v1/status
+ ```
+
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "schemaVersion": 1,
+ "kind": "phase.ai.status",
+ "safeToPrint": true,
+ "connections": [
+ {
+ "connectionId": "3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c",
+ "name": "AWS read-only",
+ "credentialId": "8a9b0c1d-2e3f-4a5b-8c7d-9e0f1a2b3c4d",
+ "credentialName": "aws-agent-readonly",
+ "credentialProvider": "aws",
+ "credentialRevision": "7",
+ "serviceType": "aws",
+ "protocol": "http",
+ "state": "ready",
+ "expiresAt": "2026-12-31T00:00:00Z"
+ }
+ ],
+ "links": {
+ "status": "http://phase.invalid/v1/status",
+ "capabilities": "http://phase.invalid/v1/capabilities",
+ "context": "http://phase.invalid/v1/context",
+ "createRequest": "http://phase.invalid/v1/requests",
+ "listRequests": "http://phase.invalid/v1/requests",
+ "pollRequest": "http://phase.invalid/v1/requests/{requestId}",
+ "cancelRequest": "http://phase.invalid/v1/requests/{requestId}/cancel",
+ "connectionEnvironment": "http://phase.invalid/v1/connections/{connectionId}/environment"
+ }
+ }
+ ```
+
+
+
+
+---
+
+## Get capabilities {{ tag: 'GET', label: '/v1/capabilities' }}
+
+
+
+
+ The versioned catalog of services this Phase instance can manage, with the IDs of any Connections this Workflow already has for each. Fetch it when status has no suitable Connection and you need to request one.
+
+ An empty `connectionIds` list means the service is supported but not connected to this Workflow: create a [setup request](#create-a-request) using the exact `serviceType` and one of the `credentialProviders`.
+
+ `clientMatchers` describe which executables and URI schemes usually involve a service. They are descriptive only and never grant anything.
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl http://phase.invalid/v1/capabilities
+ ```
+
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "schemaVersion": 1,
+ "matcherSchemaVersion": 1,
+ "kind": "phase.ai.capabilities",
+ "sessionUid": "b6f1c2d3-4e5f-4a6b-9c8d-7e6f5a4b3c2d",
+ "services": [
+ {
+ "serviceType": "aws",
+ "displayName": "Amazon Web Services",
+ "credentialProviders": ["aws", "aws_assume_role"],
+ "clientMatchers": [
+ { "kind": "executable", "values": ["aws"] }
+ ],
+ "connectionIds": ["3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c"]
+ },
+ {
+ "serviceType": "postgres",
+ "displayName": "PostgreSQL",
+ "credentialProviders": ["postgres"],
+ "clientMatchers": [
+ { "kind": "executable", "values": ["psql", "pg_dump"] },
+ { "kind": "uri_scheme", "values": ["postgres", "postgresql"] }
+ ],
+ "connectionIds": []
+ }
+ ]
+ }
+ ```
+
+
+
+
+---
+
+## Get context {{ tag: 'GET', label: '/v1/context' }}
+
+
+
+
+ Service-specific guidance written by Phase Console for this Workflow: supported operations, limitations, and how the proxy handles the service's credentials. Use it when a provider command fails or the service is unfamiliar.
+
+ ### Query parameters
+
+
+
+ Optional. Exactly one service type from status or capabilities. Omit it for the general context.
+
+
+
+ Errors: `400 invalid_context_query` for anything other than one valid `serviceType`.
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl 'http://phase.invalid/v1/context?serviceType=aws'
+ ```
+
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "schemaVersion": 1,
+ "sessionUid": "b6f1c2d3-4e5f-4a6b-9c8d-7e6f5a4b3c2d",
+ "serviceType": "aws",
+ "markdown": "Requests are re-signed with the live key. Presigned URLs and calls that mint new credentials are refused. …"
+ }
+ ```
+
+
+
+
+---
+
+## Requests
+
+When no suitable Connection exists, or a provider rejects the current credential, an Agent asks a human through a request. The human reviews it in Phase Console at the request's `approvalUrl`, creates or picks the Integration credential, and approves or denies it.
+
+There are two kinds:
+
+- **`setup`** asks for a new Integration credential and Connection for a service.
+- **`credential_update`** asks for a change to the credential behind an existing Connection, for example a missing permission or an expired key.
+
+A request is `pending` until a human acts. It ends as `approved`, `denied`, `cancelled`, or `expired`; pending requests expire after 7 days. A Workflow can have at most 20 pending requests (`429 pending_request_limit`).
+
+### Runtime action
+
+An approved request tells the runtime what the approval changed:
+
+| `runtimeAction` | Meaning | What to do |
+| --- | --- | --- |
+| `retry` | The proxy already applied the change without changing what the Agent's processes see. | Retry the operation. |
+| `restart_required` | Decoys, identifiers, routes or the process environment changed. | The background proxy that `phase ai enable` set up recycles its session on its own, and the next command picks up the change. Relaunch `phase ai run`. |
+
+An approved `setup` normally returns `restart_required`. An approved `credential_update` returns `retry` unless the change affected what processes see.
+
+---
+
+## Create a request {{ tag: 'POST', label: '/v1/requests' }}
+
+
+
+
+ Ask a human for a new or updated Integration credential.
+
+ ### Body
+
+
+
+ `setup` or `credential_update`.
+
+
+ Required. A provider from capabilities (for `setup`) or status (for `credential_update`).
+
+
+ Required. Up to 64 characters. A descriptive name for the credential, saying what it is for.
+
+
+ Required. Up to 16 KiB. Explain what access is needed and why, and recommend the narrowest practical setup. Never include credential values; Console rejects credential-shaped text.
+
+
+ `setup` only, and required for it. The exact service type from capabilities.
+
+
+ `credential_update` only, and required for it. From status.
+
+
+ `credential_update` only, and required for it. From status.
+
+
+ Optional. A stable key for the purpose. Sending the same `dedupKey` again for the same target returns the existing request instead of asking the human twice; sending it for a different target returns `409 dedup_key_conflict`.
+
+
+ Optional. Links a credential update to an earlier request.
+
+
+
+ ### Query parameters
+
+
+
+ Optional. Wait up to this many seconds (0 to 300) for the human to act before responding, so a quick approval comes back in the same response.
+
+
+
+ A new request returns `201`; a repeated `dedupKey` returns the existing request with `200`.
+
+ A pending response includes `approvalUrl`, the Console page where the human reviews the request, and `pollUrl`, the local URL to poll. Show `approvalUrl` to the human exactly as returned, then poll `pollUrl`.
+
+
+
+
+
+
+ ```bash {{ title: 'Setup' }}
+ curl 'http://phase.invalid/v1/requests?wait=60' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "kind": "setup",
+ "credentialProvider": "postgres",
+ "credentialName": "Analytics read-only database",
+ "serviceType": "postgres",
+ "markdown": "Run read-only reporting queries on the analytics database. Recommended: a role with SELECT on the reporting schema only.",
+ "dedupKey": "analytics-readonly-db"
+ }'
+ ```
+
+ ```bash {{ title: 'Credential update' }}
+ curl http://phase.invalid/v1/requests \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "kind": "credential_update",
+ "connectionId": "3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c",
+ "credentialId": "8a9b0c1d-2e3f-4a5b-8c7d-9e0f1a2b3c4d",
+ "credentialProvider": "aws",
+ "credentialName": "aws-agent-readonly",
+ "markdown": "s3:PutObject on acme-artifacts was denied. Please allow s3:PutObject on arn:aws:s3:::acme-artifacts/*.",
+ "dedupKey": "aws-readonly-s3-put"
+ }'
+ ```
+
+
+
+ ```json {{ title: 'Pending' }}
+ {
+ "schemaVersion": 1,
+ "id": "5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f",
+ "status": "pending",
+ "kind": "setup",
+ "credentialProvider": "postgres",
+ "credentialName": "Analytics read-only database",
+ "serviceType": "postgres",
+ "approvalUrl": "https://console.phase.dev/acme/agents/requests?request=5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f&action=setup",
+ "pollUrl": "http://phase.invalid/v1/requests/5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f",
+ "progress": { "stage": "awaiting_credentials" },
+ "requestExpiresAt": "2026-11-05T09:00:00Z"
+ }
+ ```
+
+ ```json {{ title: 'Approved' }}
+ {
+ "schemaVersion": 1,
+ "id": "5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f",
+ "status": "approved",
+ "kind": "setup",
+ "credentialId": "0e1f2a3b-4c5d-4e6f-8a7b-9c0d1e2f3a4b",
+ "connectionId": "7d6c5b4a-3e2f-4d1c-9b0a-8f7e6d5c4b3a",
+ "grantId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
+ "runtimeAction": "restart_required",
+ "resolvedAt": "2026-10-29T09:12:30Z"
+ }
+ ```
+
+ ```json {{ title: 'Denied' }}
+ {
+ "schemaVersion": 1,
+ "id": "5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f",
+ "status": "denied",
+ "kind": "setup",
+ "resolutionNote": "Use the existing deploy bot account instead.",
+ "resolvedAt": "2026-10-29T09:12:30Z"
+ }
+ ```
+
+
+
+
+---
+
+## Poll a request {{ tag: 'GET', label: '/v1/requests/:requestId' }}
+
+
+
+
+ Get one request. With `wait`, the proxy waits up to that many seconds (0 to 300) for the request to leave `pending`, and returns it as `pending` if time runs out. The response has the same shape as [Create a request](#create-a-request).
+
+ Keep polling the same request while it is pending. A denied request may include a `resolutionNote` from the human.
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl 'http://phase.invalid/v1/requests/5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f?wait=300'
+ ```
+
+
+
+
+
+
+---
+
+## List pending requests {{ tag: 'GET', label: '/v1/requests' }}
+
+
+
+
+ The Workflow's pending requests, so an Agent can resume waiting after a restart.
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl http://phase.invalid/v1/requests
+ ```
+
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "schemaVersion": 1,
+ "requests": [
+ {
+ "id": "5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f",
+ "status": "pending",
+ "kind": "setup",
+ "credentialProvider": "postgres",
+ "credentialName": "Analytics read-only database",
+ "serviceType": "postgres",
+ "approvalUrl": "https://console.phase.dev/acme/agents/requests?request=5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f&action=setup",
+ "pollUrl": "http://phase.invalid/v1/requests/5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f"
+ }
+ ]
+ }
+ ```
+
+
+
+
+---
+
+## Cancel a request {{ tag: 'POST', label: '/v1/requests/:requestId/cancel' }}
+
+
+
+
+ Cancel a pending request. The body must be empty or `{}`. Agents should only cancel when the human asks. Returns the request with `"status": "cancelled"`.
+
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl -X POST http://phase.invalid/v1/requests/5c4d3e2f-1a0b-4c9d-8e7f-6a5b4c3d2e1f/cancel \
+ -H 'Content-Type: application/json' -d '{}'
+ ```
+
+
+
+
+
+
+---
+
+## Get a Connection's environment {{ tag: 'GET', label: '/v1/connections/:connectionId/environment' }}
+
+
+
+
+ The process environment for one Connection: the proxy URL with the username `phase.`, the CA variables, and that Connection's decoys, plus the variables to unset. `phase ai exec --connection` uses it to run one command against a chosen Connection when a service has several.
+
+
+ This response contains the proxy password. Agents should not fetch, print or store it; run `phase ai exec --connection ` instead.
+
+
+ Errors: `400 invalid_connection_id`, `404 connection_unavailable`, and `409 connection_environment_unavailable` (retryable) when the environment can't be built.
+
+
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "schemaVersion": 1,
+ "connectionId": "3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c",
+ "configGeneration": 4,
+ "processEnvironment": {
+ "set": {
+ "PHASE_AI_ENABLED": "1",
+ "HTTPS_PROXY": "http://phase.3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c:@127.0.0.1:9543",
+ "HTTP_PROXY": "http://phase.3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c:@127.0.0.1:9543",
+ "NO_PROXY": "127.0.0.1,localhost,::1",
+ "AWS_ACCESS_KEY_ID": "",
+ "AWS_SECRET_ACCESS_KEY": ""
+ },
+ "unset": ["AWS_PROFILE", "AWS_SESSION_TOKEN", "PHASE_SERVICE_TOKEN", "PHASE_AGENT_TOKEN"]
+ }
+ }
+ ```
+
+
+
+
+---
+
+## Get the relay bootstrap {{ tag: 'GET', label: '/v1/bootstrap' }}
+
+
+
+
+ Relay only. A POSIX `sh` script (`Content-Type: text/x-shellscript`) that sets a sandbox up to use the relay. `phase relay start` prints the one-line command that fetches and runs it. See [Phase AI relay](/cli/ai/relay) for what it does.
+
+ The script contains the proxy credential and the Workflow's decoys, never live credential material. Errors: `503 agent_session_unavailable` while the relay's session refreshes, `502 relay_bootstrap_unavailable`.
+
+
+
+
+ ```bash {{ title: 'Sandbox shell' }}
+ eval "$(curl -fsS --proxy 'https://phase:@relay.example.ts.net:9543' http://phase.invalid/v1/bootstrap)"
+ ```
+
+
+
+
+---
+
+## Session routes
+
+These routes manage the proxy's session. Agents don't need them; they are used by the CLI and by tooling.
+
+| Route | Available | What it does |
+| --- | --- | --- |
+| `POST /v1/refresh` | Local and relay | Re-reads the Workflow's configuration from Console now. Body empty or `{}`. Agents should not call it. |
+| `POST /v1/rotate` | Local only | Rotates the proxy's session credential with Console. No body. The proxy capability does not change. |
+| `POST /v1/revoke` | Local only | Revokes the session in Console and stops the proxy. No body. `phase ai disable` uses it. |
+| `GET /v1/discover` | Local only | The Console configuration for this session: Connections, hosts and bindings, never live credentials. For diagnostics. |
+
+The proxy also serves its full runtime manifest at `GET /.well-known/agents`. The CLI reads it to build a managed command's environment. It contains the proxy password, decoys and the CA certificate, so Agents must not fetch, print or store it; use [status](#get-status) instead.
+
+## Proxied traffic
+
+Everything not sent to `phase.invalid` is ordinary proxied traffic. Requests to hosts bound to one of the Workflow's Connections are intercepted, checked, and sent upstream with the live credential in place of the decoy. Other hosts pass through untouched, unless the proxy runs with `--lockdown`, which blocks them.
+
+Every response to bound traffic, and every refusal, carries an `X-Phase-Event-Id` header with the ID of the event the proxy reported to Console for that request. It contains no credential material. Quote it when reporting a problem so the human can find the request in Console. AWS-style error responses repeat it as `RequestId`. Pass-through traffic has no event and no header.
+
+Failures on bound traffic use the error envelope above, except for AWS Connections, which return an AWS-style XML error. Failures tied to a Connection also set `X-Phase-Connection-Id` and `X-Phase-Grant-Id`.
+
+| Code | Status | Meaning |
+| --- | --- | --- |
+| `agent_connection_denied` | 403 | The Connection is not authorized for this request. |
+| `credential_minting_blocked` | 403 | The call would mint new credentials (for example `sts:GetSessionToken` or `iam:CreateAccessKey`), which the proxy never allows. |
+| `agent_credential_injection_failed` | 403 | The live credential could not be injected, for example because the request was not signed with the decoy. |
+| `ambiguous_agent_binding` | 403 | Several Connections match and none was selected. Use `phase ai exec --connection`. |
+| `unbound_host_blocked` | 403 | The host is not bound to the Workflow and the proxy runs with `--lockdown`. |
+| `agent_binding_unavailable` | 503 | The session is recycling. Retry shortly. |
+| `upstream_unavailable` | 502 | The upstream service could not be reached. |
diff --git a/src/pages/cli/ai/index.mdx b/src/pages/cli/ai/index.mdx
new file mode 100644
index 00000000..5bfd5e2b
--- /dev/null
+++ b/src/pages/cli/ai/index.mdx
@@ -0,0 +1,218 @@
+import { Tag } from '@/components/Tag'
+import { DocActions } from '@/components/DocActions'
+
+export const metadata = {
+ title: 'Phase AI',
+ description:
+ 'Give AI coding agents workflow-scoped access to third-party services through the Phase CLI, without exposing live credentials.',
+}
+
+CLI
+
+# Phase AI
+
+Phase AI gives AI coding agents access to third-party services, such as HTTP APIs, AWS and PostgreSQL, through Connections approved in the Phase Console. The Agent's processes only ever see decoy credentials. A local proxy run by the Phase CLI swaps them for the live credential on the way out, enforces which Connections the Agent can use, and blocks calls that would mint new credentials. {{ className: 'lead' }}
+
+
+
+## How it works
+
+- An **Agent** is an AI coding agent registered in the Phase Console. Each Agent has one or more **Workflows**, and each Workflow has its own **Connections**.
+- A **Connection** links a Workflow to a service through an **Integration credential**, for example an AWS access key or a PostgreSQL login.
+- On your machine, the CLI runs a proxy at `127.0.0.1:9543` (and a PostgreSQL adapter at `127.0.0.1:9544` when the Workflow has a PostgreSQL Connection). Processes behind it get decoy credentials and proxy settings in their environment.
+- When a request goes to a host bound to one of the Workflow's Connections, the proxy checks it, replaces the decoy with the live credential, and reports an event to the Console. Requests to other hosts pass through untouched.
+- Agents use the [Phase AI control API](/cli/ai/control-api) at `http://phase.invalid` to see their Connections and to ask a human for a new or updated credential. The human approves the request in the Console.
+
+The live credential never leaves the proxy, and the Agent never sees your Phase login.
+
+## Prerequisites
+
+- The [Phase CLI](/cli/install), installed and up to date.
+- An Agent and a Workflow in the Phase Console, with at least one Connection, or permission to approve the Agent's requests for one.
+- A supported harness: Claude Code, Cursor, Codex, OpenCode, Devin (preview) or VS Code Copilot. Any other Agent can run through [`phase ai run`](#run-an-agent-or-a-command).
+
+## Set up
+
+### 1. Log in
+
+Phase AI needs a login that names a Workflow. There are two ways to get one.
+
+**With an Agent token** (recommended). Create a token for the Agent's Workflow in the Phase Console, then log in with it:
+
+```fish
+phase auth --mode token
+```
+
+Paste the token when prompted. It looks like `pss_agent:v1:…`. The token is stored only in your OS keyring, and the Workflow comes from the token itself.
+
+```
+✅ AI Agent authentication successful: release-bot / Default (acme). This login can use only phase ai commands.
+```
+
+An Agent token can only be used with `phase ai` and `phase relay` commands. It cannot read application secrets: `phase secrets`, `phase run`, `phase shell` and the other secrets commands refuse it.
+
+**With your own login.** If you are logged in with `phase auth` or a Personal Access Token, set a default Workflow when you enable Phase AI with `phase ai enable --workflow `, or pass `--workflow` to `phase ai run` and `phase ai exec`.
+
+### 2. Enable Phase AI for your harness
+
+Run this yourself, in your own terminal. AI agents are not allowed to run it.
+
+```fish
+phase ai enable --harness claude-code
+```
+
+Use `claude-code`, `cursor`, `codex`, `opencode`, `devin` or `copilot`. Without `--harness`, the command asks which harness to set up. Run it again with another `--harness` to add more; existing integrations stay installed.
+
+`phase ai enable`:
+
+1. Creates a local certificate authority (CA) for the proxy, and offers to trust it for your user. See [The proxy CA](#the-proxy-ca).
+2. Installs two skills for the harness: `phase-cli-ai-relay`, which teaches the Agent to use the proxy, Connections and requests, and `phase-cli-app-secrets`, for Phase application secrets.
+3. Installs the harness's hook or plugin, which starts the proxy in the background when the Agent needs it.
+4. Asks whether AI agents may read secret values from `phase secrets` commands. Pass `--mask` or `--no-mask` to answer without a prompt.
+
+It ends with the steps to take before the harness can use Phase.
+
+### 3. Restart the harness
+
+Fully quit and restart the harness, start a new chat or session, and repeat your original prompt. For Codex, first open the Codex CLI, run `/hooks`, and trust every hook from `phase-ai-bootstrap@phase-cli-local`.
+
+## How each harness uses Phase
+
+| Harness | What `phase ai enable` installs | How commands use Phase |
+| --- | --- | --- |
+| Claude Code | Skills in `~/.claude/skills/` and the `phase-ai-bootstrap` hook plugin | Automatic. Every shell command uses Phase-managed credentials while the proxy runs. |
+| OpenCode | Skills in `~/.config/opencode/skills/` and the plugin `~/.config/opencode/plugins/phase-ai-bootstrap.js` | Automatic, as for Claude Code. |
+| Cursor | Skills in `~/.cursor/skills/` and the plugin `~/.cursor/plugins/local/phase-ai-bootstrap/` | Explicit. Ordinary commands keep their usual credentials; the Agent runs Phase-managed commands with `phase ai exec`. |
+| Codex | Skills in `~/.agents/skills/` and the `phase-ai-bootstrap` plugin from a local marketplace (needs the Codex CLI on `PATH`) | Explicit, as for Cursor. |
+| Devin (preview) | Skills in `~/.agents/skills/` and hooks in Devin's `config.json` | Explicit, as for Cursor. |
+| VS Code Copilot | Skills in `~/.copilot/skills/` only | Explicit, with `phase ai exec`. |
+
+In Claude Code and OpenCode, the harness's shell loads the Phase AI environment before each command, so provider CLIs and HTTP clients use the Workflow's Connections without a wrapper. Each session and prompt carries a `Phase AI:` status line. If the proxy isn't running, commands run with your usual credentials.
+
+
+In Codex's default sandbox, each Phase call needs Codex's network approval. To skip it, set `network_access = true` under `[sandbox_workspace_write]` in `~/.codex/config.toml`.
+
+
+## Check status
+
+```fish
+phase ai status
+```
+
+```
+Phase AI: enabled, local proxy
+Harnesses: claude-code, codex
+Login: release-bot, Workflow Default @ https://console.phase.dev
+Proxy: running (pid 48213, up 1h05m)
+Connections: Analytics DB (postgres): ready
+ AWS prod (aws): expired
+Environment: /Users/alex/.phase/ai/env.sh (proxy routing active)
+CA: /Users/alex/.phase/ai/ca.pem, expires 2027-01-20
+Skills: /Users/alex/.claude/skills/phase-cli-ai-relay/SKILL.md
+```
+
+Status never sends a credential. It reads local files and asks the running proxy for its [status](/cli/ai/control-api#get-status). A Connection is `ready`, `expired` (its credential's expiry has passed) or `unavailable`.
+
+## Run an Agent or a command
+
+`phase ai enable` must have been run first; both commands need Phase AI to be enabled.
+
+### `phase ai exec`
+
+Run one command with Phase-managed credentials:
+
+```fish
+phase ai exec -- aws s3 ls
+```
+
+If a Phase AI proxy is already running, because a harness started it or because you are inside a Phase-managed shell, `exec` reuses it. Otherwise it starts a short-lived proxy and session for the command and closes them when the command exits. The command's exit code is passed through.
+
+When the Workflow has several Connections for one service, pick one with `--connection` and the Connection ID from `phase ai status`:
+
+```fish
+phase ai exec --connection 3f2b8c1e-5a7d-4e9f-b0c4-1d2e3f4a5b6c -- aws sts get-caller-identity
+```
+
+Without it, a request that matches more than one Connection is refused (`ambiguous_agent_binding`).
+
+### `phase ai run`
+
+Launch an Agent harness with every command it runs behind the proxy:
+
+```fish
+phase ai run -- claude
+```
+
+`run` recognises `claude`, `cursor-agent`, `codex`, `opencode`, `devin`, `goose` and `amp`. For any other launcher, pass a label with `--harness`. For one-off commands use `exec` instead.
+
+A `run` session can't be renewed in place. When it expires, or when an approved request needs a restart (`runtimeAction: restart_required`), the CLI stops the Agent and asks you to run `phase ai run` again.
+
+### Options
+
+| Flag | Command | Description |
+| --- | --- | --- |
+| `--workflow ` | `run`, `exec` | The Agent Workflow to use. Defaults to the one set with `phase ai enable --workflow`. Ignored with an Agent token login, which names its own Workflow. |
+| `--connection ` | `exec` | The Connection to use when a service has several. |
+| `--harness ` | `run` | A label for a launcher `run` doesn't recognise. |
+| `--listen ` | `run`, `exec` | The proxy's loopback address. Default `127.0.0.1:9543`. |
+| `--lockdown` | `run`, `exec` | Block hosts that aren't bound to a Connection, instead of passing them through. |
+
+### The process environment
+
+Processes behind the proxy get:
+
+| Variable | Value |
+| --- | --- |
+| `PHASE_AI_ENABLED` | `1` |
+| `HTTP_PROXY`, `HTTPS_PROXY` (and lowercase) | The proxy URL, with a per-process password that only works with this proxy. |
+| `NO_PROXY` (and lowercase) | `127.0.0.1,localhost,::1`, plus your own entries that don't cover a bound host. |
+| `PHASE_AI_CA_BUNDLE`, `NODE_EXTRA_CA_CERTS` | A CA bundle that includes the proxy CA. |
+| `SSL_CERT_FILE`, `REQUESTS_CA_BUNDLE`, `CURL_CA_BUNDLE`, `GIT_SSL_CAINFO`, `PIP_CERT`, `DENO_CERT` and similar | The same bundle, when the CLI found your system's CA store to merge it with. |
+| Provider variables | Decoys and settings for each Connection, for example `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_REGION`, or `PGHOST`, `PGPORT`, `PGUSER` and `PGPASSWORD`. Conflicting variables such as `AWS_PROFILE` or `DATABASE_URL` are unset. |
+
+`PHASE_SERVICE_TOKEN` and `PHASE_AGENT_TOKEN` are always removed. When two Connections share a service, neither one's provider variables are set; use `--connection`.
+
+## Supported services
+
+Phase Console defines which services Phase AI can manage; Agents read the current list from [`/v1/capabilities`](/cli/ai/control-api#get-capabilities).
+
+- **AWS**: requests are signed with the decoy key and re-signed by the proxy with the live key. Presigned URLs are not supported, and calls that mint new credentials (such as `sts:AssumeRole`, `sts:GetSessionToken`, `iam:CreateAccessKey` and `ecr:GetAuthorizationToken`) are refused. Live keys are redacted from responses.
+- **PostgreSQL**: clients connect to the local adapter on port `9544` over TLS (`PGSSLMODE=verify-full`) with the decoy password, and the proxy logs in to the database as the real user. Replication connections are refused.
+
+## Requests and approvals
+
+When an Agent needs a service the Workflow has no Connection for, or a provider rejects the current credential, the Agent creates a request through the [control API](/cli/ai/control-api#requests) and shows you a link to it in the Phase Console. There you create or choose the Integration credential and approve or deny the request. The Agent waits for your decision and then continues.
+
+Agents never ask you to paste a credential into the chat or into a request.
+
+## The proxy CA
+
+The proxy inspects traffic to bound hosts over TLS with certificates from a local CA. `phase ai enable` creates it in `~/.phase/ai/ca.pem` and keeps its private key in your OS keyring.
+
+- The CA is valid for 90 days and renews automatically when 14 days or less remain, on the next `phase ai enable` or proxy start. After a renewal, run `phase ai enable` again to trust the new CA.
+- Processes behind the proxy trust the CA through their environment (`SSL_CERT_FILE`, `NODE_EXTRA_CA_CERTS`, `REQUESTS_CA_BUNDLE`, `AWS_CA_BUNDLE` and similar), whether or not you trust it in your OS. Trusting it in your user trust store matters for browsers, and for Go programs on macOS and Windows.
+- Trust is only ever added for your user, never system-wide, and never needs `sudo`:
+ - **macOS**: the login keychain. macOS asks for your login password or Touch ID once.
+ - **Windows**: your user Root store. Windows shows a security warning to confirm.
+ - **Linux**: your NSS database in `~/.pki/nssdb`, which needs NSS `certutil` (`libnss3-tools` on Debian and Ubuntu, `nss-tools` on Fedora, RHEL and Alpine, `nss` on Arch, `mozilla-nss-tools` on openSUSE). Without it, enable skips the step and tells you which package to install.
+
+Pass `--trust-ca` to trust the CA without a prompt, or `--trust-ca=false` to decline.
+
+## Disable Phase AI
+
+```fish
+phase ai disable
+```
+
+`phase ai disable` stops the proxy, removes the Phase AI environment so the next shell command uses your usual credentials, and removes the hooks, plugins and `phase-cli-ai-relay` skill it installed. Customized files are left alone. It keeps the `phase-cli-app-secrets` skill, the CA, your login, and your settings in `~/.phase/ai.json`, so `phase ai enable` restores the same setup later.
+
+Run it yourself; AI agents are not allowed to.
+
+## Security
+
+- **Live credentials stay in the proxy.** Agent processes only see decoys. The proxy checks each request against the Workflow's Connections before swapping the decoy for the live credential.
+- **No new credentials.** Calls that would mint new credentials, such as `sts:GetSessionToken` or `iam:CreateAccessKey`, are refused.
+- **Every request is recorded.** The proxy reports an event to the Console for each request to a bound host, and returns its ID in the `X-Phase-Event-Id` response header so you can find it.
+- **Your login stays in the CLI.** The Agent never sees your Phase token or the proxy's Console session. The proxy URL's password only works with the running proxy.
+- **Setup stays with you.** AI agents can't run `phase ai enable` or `phase ai disable`.
+- **Application secrets are guarded.** When the CLI detects an AI agent, `phase secrets` commands redact secret values according to your `--mask` choice (sealed values are always hidden), `phase run` refuses commands that dump the environment, and `phase shell` is refused.
diff --git a/src/pages/cli/ai/relay.mdx b/src/pages/cli/ai/relay.mdx
new file mode 100644
index 00000000..228f69c0
--- /dev/null
+++ b/src/pages/cli/ai/relay.mdx
@@ -0,0 +1,109 @@
+import { Tag } from '@/components/Tag'
+import { DocActions } from '@/components/DocActions'
+
+export const metadata = {
+ title: 'Phase AI relay',
+ description:
+ 'Run a Phase AI relay so remote Agent sandboxes that cannot run the Phase CLI can use a Workflow\'s Connections.',
+}
+
+CLI
+
+# Phase AI relay
+
+A relay is a [Phase AI](/cli/ai) proxy that remote Agent sandboxes reach over TLS. Use it when an Agent runs somewhere the Phase CLI can't, such as a container or a hosted sandbox that only has `curl` and a shell. {{ className: 'lead' }}
+
+
+
+The relay runs on a machine you control and is logged in with an Agent token. Each sandbox runs a one-line bootstrap that points it at the relay. From then on, the sandbox's commands use the Workflow's Connections through the relay, and the sandbox only ever sees decoy credentials.
+
+## Prerequisites
+
+- A machine with the [Phase CLI](/cli/install), reachable from your sandboxes.
+- A login with an **Agent token**: `phase auth --mode token`. A relay can't use your own login.
+- A DNS name for the relay (not an IP address) and a TLS certificate for it that your sandboxes already trust, for example from `tailscale cert`. The private key file must be readable only by you (mode `0600` or `0400`).
+- In each sandbox: a POSIX shell and `curl`.
+
+## Start a relay
+
+```fish
+phase relay start \
+ --advertise-host relay.example.ts.net \
+ --tls-cert relay.example.ts.net.crt \
+ --tls-key relay.example.ts.net.key
+```
+
+```
+🛰️ Phase AI relay ready
+ Proxy: https://relay.example.ts.net:9543
+ PostgreSQL: relay.example.ts.net:9544
+ Connections: Analytics DB (postgres), AWS dev (aws)
+
+Hand this line to a trusted sandbox. It contains the relay credential and stays valid until this process stops:
+
+ eval "$(curl -fsS --proxy 'https://phase:@relay.example.ts.net:9543' http://phase.invalid/v1/bootstrap)"
+
+The bootstrap installs the Phase CA, loads the Phase AI environment into that shell and future login shells, and installs the phase-cli-ai-relay skill.
+Press Ctrl+C to stop.
+```
+
+The relay's proxy listens on port `9543`. Its PostgreSQL adapter listens on the next port, `9544`, only when the Workflow has a PostgreSQL Connection. Both use your TLS certificate.
+
+On macOS, type `c` and press Enter to copy the handoff line.
+
+### Options
+
+| Flag | Description |
+| --- | --- |
+| `--advertise-host ` | Required. The DNS name sandboxes dial. The certificate must cover it. |
+| `--tls-cert ` | Required. The certificate chain (PEM) for the advertised host. |
+| `--tls-key ` | Required. The certificate's private key (PEM), readable only by you. |
+| `--tls-ca ` | For private PKI: the root certificates (PEM) that issued `--tls-cert`. Sandboxes must already trust them. By default the system trust store is used. |
+| `--listen ` | The proxy's bind address. Default `0.0.0.0:9543`. The PostgreSQL adapter binds the same host on the next port. |
+| `--lockdown` | Block hosts that aren't bound to a Connection, instead of passing them through. |
+
+Without `--lockdown`, traffic to unbound hosts passes through the relay only to public IP addresses.
+
+## Bootstrap a sandbox
+
+Run the handoff line in the sandbox's shell:
+
+```bash
+eval "$(curl -fsS --proxy 'https://phase:@relay.example.ts.net:9543' http://phase.invalid/v1/bootstrap)"
+```
+
+The bootstrap:
+
+1. Writes the Phase CA to `~/.phase/ai/phase-ca.pem`, and merges it with the sandbox's system CA store into `~/.phase/ai/ca-bundle.pem`.
+2. Writes `~/.phase/ai/env.sh` with the relay's proxy settings, CA variables, the Workflow's decoys and the PostgreSQL adapter settings.
+3. Installs the `phase-cli-ai-relay` skill for Claude Code, Cursor, Codex, Devin, OpenCode and VS Code Copilot.
+4. Loads `env.sh` into the current shell, and adds a loader to `~/.profile` (and to `~/.bashrc` and `~/.zshrc` if they exist) so new login shells load it too.
+
+```
+Phase AI relay environment loaded for Analytics DB (postgres), AWS dev (aws). New login shells load ~/.phase/ai/env.sh automatically.
+```
+
+Running it again is safe. The bootstrap contains the relay credential and the Workflow's decoys, but never a live credential.
+
+
+The handoff line contains the relay's credential. Anyone with it can use the Workflow's Connections through the relay until the relay stops. Only give it to sandboxes you trust, and don't commit it.
+
+
+## While the relay runs
+
+- **Sessions renew in place.** When the relay's session with Phase Console expires or the Workflow's Connections change, the relay opens a new one without interrupting sandboxes. The relay credential stays the same, and decoys from earlier sessions keep working.
+
+ ```
+ 2026-10-29T09:12:30Z Phase AI session changed; opening a new one.
+ 2026-10-29T09:12:31Z Phase AI session refreshed; sandboxes keep working.
+ ```
+
+- **Console outages are retried.** If the relay can't open a session, it retries with a backoff of up to 30 seconds. If the Agent token is rejected, the relay stops.
+- **Requests work as usual.** Agents in sandboxes use the [control API](/cli/ai/control-api) through the relay to check status and request Connections. `GET /v1/discover`, `POST /v1/rotate` and `POST /v1/revoke` are local-only and not available through a relay.
+- **The proxy CA renews every 90 days.** After a renewal, bootstrap your sandboxes again.
+
+Stop the relay with Ctrl+C. The handoff credential stops working as soon as it exits.
+
+```
+Phase AI relay stopped; the handoff credential is no longer valid.
+```
diff --git a/src/pages/cli/commands.mdx b/src/pages/cli/commands.mdx
index 0f1029dd..0d715f5f 100644
--- a/src/pages/cli/commands.mdx
+++ b/src/pages/cli/commands.mdx
@@ -44,9 +44,13 @@ Commands:
dynamic-secrets lease get 🔍 Get leases for a dynamic secret
dynamic-secrets lease renew 🔁 Renew a lease
dynamic-secrets lease revoke 🗑️ Revoke a lease
- ai enable 🪄 Enable AI integrations and configure secret visibility
+ ai enable 🪄 Enable the local Phase AI credential proxy
ai disable 🚫 Disable AI integrations
+ ai status 📡 Show Phase AI setup and proxy health
ai skill 📄 Print the Phase AI skill document
+ ai run 🚀 Launch an AI Agent behind the Phase AI credential proxy
+ ai exec ⚡ Execute one command behind a transient Phase AI credential proxy
+ relay start 🛰️ Run a Phase AI relay for remote Agent sandboxes
users whoami 🙋 See details of the current user
users switch 🪄 Switch between Phase users, orgs and hosts
users logout 🏃 Logout from phase-cli
@@ -110,13 +114,15 @@ Please authenticate via the Phase Console: https://console.phase.dev/webauth/OTM
This opens the Phase Console in a new tab. Enter your `sudo` password when prompted. The CLI securely receives your credentials via encrypted POST requests to finalize authentication. If you are already authenticated, it will display your email address and provide instructions for switching accounts.
-2. **Token**: This allows you to authenticate to Phase directly using a Personal Access Token (PAT) or a Service Account Token that you may have manually created in the Phase Console.
+2. **Token**: This allows you to authenticate to Phase directly using a Personal Access Token (PAT), a Service Account Token, or an Agent token that you may have manually created in the Phase Console.
For `token` mode, provide the following:
- Host URL - _Only for Self-hosted instances_
- Email
-- Personal Access Token (PAT) or a Service Account Token
+- Personal Access Token (PAT), Service Account Token, or Agent token
+
+An Agent token (`pss_agent:v1:…`) logs in as an AI Agent and its Workflow, for use with [Phase AI](/cli/ai). It is stored only in your OS keyring and can only be used with `phase ai` and `phase relay` commands.
Obtain a Personal Access Token (PAT) from the [Phase Console](https://console.phase.dev) by going to Access Control -> Authentication -> Personal Access Tokens -> + `Create Token`.
@@ -1083,40 +1089,35 @@ Notes:
## 🥷 `ai`
-Configure AI integrations for Phase. The `ai` command group controls how AI coding agents interact with your Phase secrets. When enabled, the CLI installs a skill document to your AI tool's global skill directory and applies security guardrails automatically.
+Give AI coding agents workflow-scoped access to third-party services through [Phase AI](/cli/ai). Agents run behind a local proxy that swaps decoy credentials for the live ones in the Workflow's Connections. The `ai` commands also control how agents can read Phase application secrets.
-See [AI agent integration pages](/integrations/agents/claude-code) for setup guides for each supported tool.
+See [Phase AI](/cli/ai) for a setup guide and the [Phase AI control API](/cli/ai/control-api) for the API Agents use.
### 🪄 `ai enable`
-Enable AI integrations: installs the Phase skill document for your chosen AI agent and configures secret visibility. This command **cannot be run by AI agents** — it must be run by the user directly.
+Enable Phase AI for a harness. It creates the proxy's CA and offers to trust it, installs the Phase skills and the harness's hook or plugin, and asks whether AI agents may read secret values. This command **cannot be run by AI agents**; run it yourself.
Usage:
```fish
-# Interactive — select AI agent and visibility
+# Interactive: choose the harness, CA trust and secret visibility
> phase ai enable
# Non-interactive
-> phase ai enable --mask --path ~/.claude/skills/phase-cli/SKILL.md
-> phase ai enable --no-mask --path ~/.cursor/skills/phase-cli/SKILL.md
+> phase ai enable --harness claude-code --trust-ca --mask
+> phase ai enable --harness codex --workflow
```
-Interactive mode first asks which AI agent to install for, then prompts for secret visibility:
+Options:
-```
-🪄 Install Phase AI skill for
-❯ Claude Code (global) → ~/.claude/skills/phase-cli/SKILL.md
- Cursor (global) → ~/.cursor/skills/phase-cli/SKILL.md
- VS Code Copilot (global) → ~/.copilot/skills/phase-cli/SKILL.md
- Codex (global) → ~/.agents/skills/phase-cli/SKILL.md
- OpenCode (global) → ~/.config/opencode/skills/phase-cli/SKILL.md
- Custom path...
+- `--harness`: `claude-code`, `cursor`, `codex`, `opencode`, `devin` or `copilot`. Run it again with another harness to add one; existing integrations stay installed.
+- `--workflow`: the default Agent Workflow for `phase ai run` and `phase ai exec` when you are logged in as yourself. Not needed with an Agent token login.
+- `--trust-ca`: trust the Phase AI CA for your user without a prompt. `--trust-ca=false` declines.
+- `--mask` / `--no-mask`: hide or show secret values from `phase secrets` commands run by AI agents.
+- `--path`: install the skill to a custom path.
+- `--mode`: the proxy mode. Only `local` is supported.
-🔒 Mask secret values from AI agents?
-❯ Yes — mask secret values (recommended for production)
- No — allow AI to read secret values (e.g. development environments)
-```
+Secret visibility:
Sealed secret values are **always** hidden from AI tools regardless of this setting. This is a hard security boundary — sealed secrets (API keys, tokens, passwords) can only be created/updated with random generation and their values never appear in AI conversations.
@@ -1132,15 +1133,52 @@ Sealed secret values are **always** hidden from AI tools regardless of this sett
### 🚫 `ai disable`
-Disable AI integrations. Removes `~/.phase/ai.json` and uninstalls the skill document from all known AI agent directories.
+Disable Phase AI. Stops the proxy, removes the Phase AI shell environment so commands use your usual credentials again, and removes the hooks, plugins and runtime skill that `phase ai enable` installed. Your settings, the CA and the `phase-cli-app-secrets` skill are kept for a later `phase ai enable`. AI agents cannot run it.
```fish
> phase ai disable
```
+### 📡 `ai status`
+
+Show Phase AI's setup and health: harnesses, login and Workflow, the proxy, the Workflow's Connections and their state, the CA and the installed skills. It never sends credentials.
+
+```fish
+> phase ai status
+```
+
+### 🚀 `ai run`
+
+Launch an AI Agent harness behind the Phase AI proxy.
+
+```fish
+> phase ai run -- claude
+```
+
+Options:
+
+- `--workflow`: the Agent Workflow to use. Defaults to the one from `phase ai enable --workflow`; ignored with an Agent token login.
+- `--harness`: a label for a launcher `run` doesn't recognise.
+- `--listen`: the proxy's loopback address. Default `127.0.0.1:9543`.
+- `--lockdown`: block hosts that aren't bound to a Connection.
+
+### ⚡ `ai exec`
+
+Run one command behind the Phase AI proxy. It reuses a running Phase AI proxy when there is one, and otherwise starts a short-lived one for the command.
+
+```fish
+> phase ai exec -- aws s3 ls
+> phase ai exec --connection -- psql -c 'select 1'
+```
+
+Options:
+
+- `--connection`: the Connection to use when a service has several.
+- `--workflow`, `--listen`, `--lockdown`: as for `ai run`.
+
### 📄 `ai skill`
-Print the raw Phase AI skill document to stdout. Useful for piping to a custom location or inspecting the skill content.
+Print the Phase AI runtime skill (`phase-cli-ai-relay`) to stdout.
```fish
> phase ai skill
@@ -1165,6 +1203,25 @@ When the CLI detects it is being run by an AI agent:
---
+## 🛰️ `relay`
+
+### `relay start`
+
+Run a [Phase AI relay](/cli/ai/relay): a Phase AI proxy that remote Agent sandboxes reach over TLS. Requires an Agent token login (`phase auth --mode token`) and a TLS certificate for the relay's DNS name that the sandboxes trust. It prints a one-line bootstrap to run in each sandbox.
+
+```fish
+> phase relay start --advertise-host relay.example.ts.net --tls-cert relay.crt --tls-key relay.key
+```
+
+Options:
+
+- `--advertise-host`: required. The DNS name sandboxes dial; the certificate must cover it.
+- `--tls-cert`, `--tls-key`: required. The certificate chain and its private key (PEM). The key must be readable only by you.
+- `--tls-ca`: the root certificates that issued `--tls-cert`, for private PKI.
+- `--listen`: the bind address. Default `0.0.0.0:9543`; the PostgreSQL adapter uses the next port.
+- `--lockdown`: block hosts that aren't bound to a Connection.
+
+---
## 👥 `users`
Manage users and accounts in the Phase CLI. This command includes sub-commands for user management.
diff --git a/src/pages/integrations/agents/claude-code.mdx b/src/pages/integrations/agents/claude-code.mdx
index bcefcf46..32e22276 100644
--- a/src/pages/integrations/agents/claude-code.mdx
+++ b/src/pages/integrations/agents/claude-code.mdx
@@ -1,151 +1,136 @@
import { Tag } from '@/components/Tag'
import { DocActions } from '@/components/DocActions'
-export const description = 'Integrate Phase with Claude Code'
+export const metadata = {
+ title: 'Claude Code',
+ description: 'Use Phase with Claude Code: workflow-scoped Connections to AWS and PostgreSQL, and application secrets management.',
+}
INTEGRATE
# Claude Code
-Manage Phase secrets directly from [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Claude can list, create, update, and delete secrets, run processes with injected secrets, and manage your Phase environments — all from natural language.
+Use Phase from [Claude Code](https://docs.anthropic.com/en/docs/claude-code) in two ways. {{ className: 'lead' }}
+
+- **Connections**: Claude Code uses services such as AWS and PostgreSQL through your Agent Workflow's Connections, approved in the Phase Console. It only ever sees decoy credentials; the Phase AI proxy swaps in the live ones. See [Phase AI](/cli/ai).
+- **Application secrets**: Claude Code can list, create, rotate and delete secrets in your Phase apps without reading their values.
## Prerequisites
-- [Phase CLI installed and authenticated](/cli/usage)
-- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed
+- The [Phase CLI](/cli/install), installed and up to date.
+- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed.
+- For Connections: an Agent and a Workflow in the Phase Console.
## Setup
-### 1. Enable AI integration
-
-```fish
-phase ai enable
-```
-
-Select **Claude Code** when prompted. This installs the Phase skill to `~/.claude/skills/phase-cli/SKILL.md` and configures secret visibility.
-
-You'll be asked whether AI agents can see secret values:
-- **Mask values** (recommended) — `secret` and `sealed` types show as `[REDACTED]`
-- **Show values** — `secret` and `config` types are visible; `sealed` is always hidden
+### 1. Log in
-### 2. Start using Phase in Claude Code
+For Connections, log in with an Agent token for the Agent's Workflow, created in the Phase Console:
-Open Claude Code in your project directory. You can immediately start managing secrets:
-
-```
-You: list my secrets
-You: create a DATABASE_URL as config with value postgres://localhost:5432/mydb
-You: rotate the API_KEY as a sealed secret with random base64
-You: run npm start with my secrets
+```fish
+phase auth --mode token
```
----
+For application secrets, log in as yourself with `phase auth`: Agent tokens can't access application secrets. To use Connections with your own login, set the Workflow in the next step with `--workflow `.
-## How it works
+### 2. Enable Phase for Claude Code
-The Phase CLI installs a **skill document** that teaches Claude Code how to use the Phase CLI. Claude runs Phase commands directly in your terminal — no separate server or middleware.
+Run this yourself, in your own terminal. Claude Code isn't allowed to run it.
-```
-Claude Code → phase CLI commands → Phase API
+```fish
+phase ai enable --harness claude-code
```
-The skill is installed globally at `~/.claude/skills/phase-cli/SKILL.md` and is automatically loaded by Claude Code for all projects.
+It installs:
----
-
-## Secret types and AI visibility
+- The `phase-cli-ai-relay` and `phase-cli-app-secrets` skills in `~/.claude/skills/`.
+- The `phase-ai-bootstrap` hook plugin in `~/.claude/skills/phase-ai-bootstrap/`, which starts the proxy and loads the Phase AI environment into Claude Code's shell.
-Phase supports three secret types with different security levels:
+It also creates the Phase AI CA and offers to trust it for your user (see [The proxy CA](/cli/ai#the-proxy-ca)), and asks whether Claude Code may read secret values.
-| Type | AI visibility | Description |
-| ---- | ------------- | ----------- |
-| `config` | **Always visible** | Non-sensitive configuration (ports, hosts, flags) |
-| `secret` | Controlled by `phase ai enable` | Standard encrypted secrets |
-| `sealed` | **Never visible** | Write-only secrets (API keys, tokens, passwords) |
+### 3. Restart Claude Code
-
-Sealed secret values are **never** exposed to AI agents regardless of configuration. When Claude creates or rotates a sealed secret, it uses `--random` generation — the actual value never appears in the conversation.
-
+Fully quit and restart Claude Code (or Claude Desktop), start a new chat, then repeat your original prompt.
---
-## Security guardrails
-
-The Phase CLI enforces guardrails when it detects an AI agent:
+## Using Connections
-| Guardrail | Enforcement |
-| --------- | ----------- |
-| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by CLI** |
-| `phase shell` | **Blocked entirely** in AI mode |
-| Sealed secret values in output | **Always redacted** |
-| Secret values in `phase secrets export` | **Redacted** based on type and config |
-| `phase ai enable` / `phase ai disable` | **Blocked** — must be run by user directly |
+Every shell command Claude Code runs uses the Workflow's Connections while the Phase AI proxy runs. The hook starts the proxy when Claude Code needs it, and Claude Code's shell loads the Phase AI environment before each command, so provider CLIs and HTTP clients work with no wrapper. If the proxy isn't running, commands use your usual credentials.
-### Viewing secrets out-of-band
-
-When values are hidden from the AI, view them directly in your terminal:
-
-```fish
-# View all secrets with values
-phase secrets list --show
+Each session and prompt carries a `Phase AI:` status line, so Claude knows which Connections are ready. You can also launch Claude Code behind the proxy with `phase ai run -- claude`.
-# View a specific secret
-phase secrets get SECRET_KEY
-
-# Export secrets
-phase secrets export
+```
+You: what can Phase manage here?
+You: list the S3 buckets in our dev AWS account
+You: count yesterday's orders in the analytics database
```
-Claude will suggest these commands when it cannot see values itself.
+When the Workflow has no Connection for what you asked, Claude Code creates a request and shows you a link to it in the Phase Console. Create or choose the credential there and approve the request; Claude Code waits and then carries on. See [Requests and approvals](/cli/ai#requests-and-approvals).
---
-## Example use cases
+## Managing application secrets
+
+The `phase-cli-app-secrets` skill lets Claude Code work with your Phase apps and environments without seeing sensitive values:
-### Managing secrets through conversation
+- List apps, environments and secret keys.
+- Create or rotate secrets with random values (`--random`), so the value never appears in the conversation.
+- Create and update non-sensitive `config` values.
+- Delete secrets, after confirming the app, environment and path.
```
-You: list my secrets for staging
-Claude: [runs phase secrets list --env staging]
+You: list the secret keys in staging for the backend app
+You: create STRIPE_WEBHOOK_SECRET as a sealed secret with a random value
+You: rotate API_TOKEN in development
+You: set LOG_LEVEL to debug in development
+```
-You: create STRIPE_SECRET_KEY as a sealed secret with random base64
-Claude: [runs phase secrets create STRIPE_SECRET_KEY --random base64 --length 32 --type sealed]
+Claude Code doesn't read secret values (`phase secrets get`, `phase secrets list --show`, `phase secrets export`), import `.env` files, or run `phase run` or `phase shell`. Run those yourself in a terminal. When a sensitive value has to be entered by hand, Claude Code asks you to enter it in the Phase Console or your terminal rather than in the chat.
-You: import my .env file
-Claude: [runs phase secrets import .env]
-```
+### Secret visibility
-### Running applications with secrets
+| Type | Visible to Claude Code | Description |
+| ---- | ------------------ | ----------- |
+| `config` | **Always** | Non-sensitive configuration, such as ports, hosts and flags |
+| `secret` | Your choice in `phase ai enable` (`--mask` or `--no-mask`) | Standard encrypted secrets |
+| `sealed` | **Never** | Write-only secrets, such as API keys, tokens and passwords |
-```
-You: start my dev server
-Claude: [runs phase run 'npm run dev']
+
+Sealed secret values are **never** shown to AI agents, whatever you choose. Claude Code creates and rotates them with `--random`, so the value never appears in the conversation.
+
-You: run it with staging secrets instead
-Claude: [runs phase run --env staging 'npm run dev']
-```
+---
-### Rotating secrets
+## Security guardrails
-```
-You: rotate the DATABASE_PASSWORD
-Claude: [runs phase secrets update DATABASE_PASSWORD --random hex --length 64]
-```
+| Guardrail | Enforcement |
+| --------- | ----------- |
+| Live provider credentials | **Stay in the Phase AI proxy**; Claude Code only sees decoys |
+| Calls that mint new credentials (for example `sts:GetSessionToken`) | **Blocked by the proxy** |
+| `phase ai enable` / `phase ai disable` | **Blocked**; run them yourself |
+| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by the CLI** |
+| `phase shell` | **Blocked** for AI agents |
+| Sealed secret values in output | **Always redacted** |
+| Secret values in `phase secrets` output | **Redacted** according to your visibility choice |
---
## Managing the integration
```fish
-# Update the skill (re-run after CLI upgrade)
-phase ai enable
+# Check setup, the proxy and the Workflow's Connections
+phase ai status
+
+# Refresh the skills and hook after a CLI upgrade
+phase ai enable --harness claude-code
# Remove the integration
phase ai disable
-# View the skill document
+# Print the Phase AI skill
phase ai skill
```
@@ -153,30 +138,26 @@ phase ai skill
## Troubleshooting
-### Claude doesn't know about Phase
+### Claude Code doesn't know about Phase
-Make sure the skill is installed:
+Check that the skills are installed:
```fish
-ls ~/.claude/skills/phase-cli/SKILL.md
+ls ~/.claude/skills/phase-cli-ai-relay/SKILL.md ~/.claude/skills/phase-cli-app-secrets/SKILL.md
```
-If missing, run `phase ai enable` and select Claude Code.
+If they're missing, run `phase ai enable --harness claude-code` and restart Claude Code.
-### "auth error" from commands
+### Phase-managed commands fail
-Ensure you are logged in:
+Run `phase ai status` and check the `Proxy` and `Connections` lines. A Connection must be `ready`. When Claude Code reports a Phase error, it quotes the `X-Phase-Event-Id` from the response, which you can look up in the Phase Console.
-```fish
-phase auth
-phase users whoami
-```
-
-### Project not linked
+### Authentication errors
-If commands return "no application found", link your project:
+Check who you're logged in as:
```fish
-phase apps list
-phase init --app-id "your-app-id" --env Development
+phase users whoami
```
+
+Log in again with `phase auth --mode token` for an Agent token, or `phase auth` for your own account.
diff --git a/src/pages/integrations/agents/codex.mdx b/src/pages/integrations/agents/codex.mdx
index 04e282b4..ad24d398 100644
--- a/src/pages/integrations/agents/codex.mdx
+++ b/src/pages/integrations/agents/codex.mdx
@@ -1,89 +1,174 @@
import { Tag } from '@/components/Tag'
import { DocActions } from '@/components/DocActions'
-export const description = 'Integrate Phase with OpenAI Codex'
+export const metadata = {
+ title: 'OpenAI Codex',
+ description: 'Use Phase with OpenAI Codex: workflow-scoped Connections to AWS and PostgreSQL, and application secrets management.',
+}
INTEGRATE
# OpenAI Codex
-Manage Phase secrets directly from [OpenAI Codex](https://developers.openai.com/codex/cli). Codex can list, create, update, and delete secrets, run processes with injected secrets, and manage your Phase environments — all from natural language.
+Use Phase from [OpenAI Codex](https://developers.openai.com/codex/cli) in two ways. {{ className: 'lead' }}
+
+- **Connections**: Codex uses services such as AWS and PostgreSQL through your Agent Workflow's Connections, approved in the Phase Console. It only ever sees decoy credentials; the Phase AI proxy swaps in the live ones. See [Phase AI](/cli/ai).
+- **Application secrets**: Codex can list, create, rotate and delete secrets in your Phase apps without reading their values.
## Prerequisites
-- [Phase CLI installed and authenticated](/cli/usage)
-- [OpenAI Codex CLI](https://developers.openai.com/codex/cli) installed
+- The [Phase CLI](/cli/install), installed and up to date.
+- [OpenAI Codex](https://developers.openai.com/codex/cli) installed.
+- The Codex CLI on your `PATH`, even if you use Codex Desktop. `phase ai enable` uses it to install the plugin.
+- For Connections: an Agent and a Workflow in the Phase Console.
## Setup
-### 1. Enable AI integration
+### 1. Log in
+
+For Connections, log in with an Agent token for the Agent's Workflow, created in the Phase Console:
```fish
-phase ai enable
+phase auth --mode token
```
-Select **Codex** when prompted. This installs the Phase skill to `~/.agents/skills/phase-cli/SKILL.md` and configures secret visibility.
+For application secrets, log in as yourself with `phase auth`: Agent tokens can't access application secrets. To use Connections with your own login, set the Workflow in the next step with `--workflow `.
+
+### 2. Enable Phase for Codex
+
+Run this yourself, in your own terminal. Codex isn't allowed to run it.
+
+```fish
+phase ai enable --harness codex
+```
+
+It installs:
+
+- The `phase-cli-ai-relay` and `phase-cli-app-secrets` skills in `~/.agents/skills/`.
+- The `phase-ai-bootstrap` plugin, from a Phase-owned local marketplace in `~/.phase/ai/codex-marketplace/` that `phase ai enable` registers with the Codex CLI. It starts the proxy when Codex first calls Phase.
+
+It also creates the Phase AI CA and offers to trust it for your user (see [The proxy CA](/cli/ai#the-proxy-ca)), and asks whether Codex may read secret values.
+
+### 3. Restart Codex
-You'll be asked whether AI agents can see secret values:
-- **Mask values** (recommended) — `secret` and `sealed` types show as `[REDACTED]`
-- **Show values** — `secret` and `config` types are visible; `sealed` is always hidden
+Open the Codex CLI, run `/hooks`, and trust every hook from `phase-ai-bootstrap@phase-cli-local`. Then fully quit and restart Codex (the CLI or Codex Desktop), start a new task, and repeat your original prompt.
-### 2. Start using Phase in Codex
+---
+
+## Using Connections
-Invoke the skill explicitly with `$phase-cli` or let Codex auto-detect it from task context:
+Ordinary commands keep your usual credentials. When you ask Codex to use Phase, it runs the command with `phase ai exec`, adding `--connection ` when a service has several Connections:
+```fish
+phase ai exec -- aws s3 ls
```
-You: $phase-cli list my secrets
-You: create a DATABASE_URL as config with value postgres://localhost:5432/mydb
-You: rotate the API_KEY as a sealed secret with random base64
+
+The plugin starts the Phase AI proxy the first time Codex calls Phase, and `phase ai exec` reuses it.
+
+
+In Codex's default sandbox, each Phase call needs Codex's network approval. To skip it, set `network_access = true` under `[sandbox_workspace_write]` in `~/.codex/config.toml`.
+
+
```
+You: what can Phase manage here?
+You: use Phase to list the S3 buckets in our dev AWS account
+You: use Phase to count yesterday's orders in the analytics database
+```
+
+When the Workflow has no Connection for what you asked, Codex creates a request and shows you a link to it in the Phase Console. Create or choose the credential there and approve the request; Codex waits and then carries on. See [Requests and approvals](/cli/ai#requests-and-approvals).
---
-## How it works
+## Managing application secrets
-The Phase CLI installs a **skill document** that teaches Codex how to use the Phase CLI. Codex runs Phase commands directly — no separate server or middleware.
+The `phase-cli-app-secrets` skill lets Codex work with your Phase apps and environments without seeing sensitive values:
+Invoke a skill explicitly with `$phase-cli-ai-relay` or `$phase-cli-app-secrets`, or let Codex pick it from the task.
-The skill is installed at `~/.agents/skills/phase-cli/SKILL.md`, which is the user-level skill directory scanned by Codex for all projects.
----
+- List apps, environments and secret keys.
+- Create or rotate secrets with random values (`--random`), so the value never appears in the conversation.
+- Create and update non-sensitive `config` values.
+- Delete secrets, after confirming the app, environment and path.
-## Secret types and AI visibility
+```
+You: list the secret keys in staging for the backend app
+You: create STRIPE_WEBHOOK_SECRET as a sealed secret with a random value
+You: rotate API_TOKEN in development
+You: set LOG_LEVEL to debug in development
+```
-| Type | AI visibility | Description |
-| ---- | ------------- | ----------- |
-| `config` | **Always visible** | Non-sensitive configuration (ports, hosts, flags) |
-| `secret` | Controlled by `phase ai enable` | Standard encrypted secrets |
-| `sealed` | **Never visible** | Write-only secrets (API keys, tokens, passwords) |
+Codex doesn't read secret values (`phase secrets get`, `phase secrets list --show`, `phase secrets export`), import `.env` files, or run `phase run` or `phase shell`. Run those yourself in a terminal. When a sensitive value has to be entered by hand, Codex asks you to enter it in the Phase Console or your terminal rather than in the chat.
+
+### Secret visibility
+
+| Type | Visible to Codex | Description |
+| ---- | ------------------ | ----------- |
+| `config` | **Always** | Non-sensitive configuration, such as ports, hosts and flags |
+| `secret` | Your choice in `phase ai enable` (`--mask` or `--no-mask`) | Standard encrypted secrets |
+| `sealed` | **Never** | Write-only secrets, such as API keys, tokens and passwords |
-Sealed secret values are **never** exposed to AI agents regardless of configuration.
+Sealed secret values are **never** shown to AI agents, whatever you choose. Codex creates and rotates them with `--random`, so the value never appears in the conversation.
---
## Security guardrails
-The Phase CLI enforces guardrails when it detects an AI agent:
-
-- `printenv`, `env`, `export`, `set`, `declare`, `compgen` are **blocked** inside `phase run`
-- `phase shell` is **blocked entirely** in AI mode
-- Sealed secret values are **always redacted** in output
-- `phase ai enable` / `phase ai disable` **must be run by the user** directly
+| Guardrail | Enforcement |
+| --------- | ----------- |
+| Live provider credentials | **Stay in the Phase AI proxy**; Codex only sees decoys |
+| Calls that mint new credentials (for example `sts:GetSessionToken`) | **Blocked by the proxy** |
+| `phase ai enable` / `phase ai disable` | **Blocked**; run them yourself |
+| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by the CLI** |
+| `phase shell` | **Blocked** for AI agents |
+| Sealed secret values in output | **Always redacted** |
+| Secret values in `phase secrets` output | **Redacted** according to your visibility choice |
---
## Managing the integration
```fish
-# Update the skill (re-run after CLI upgrade)
-phase ai enable
+# Check setup, the proxy and the Workflow's Connections
+phase ai status
+
+# Refresh the skills and plugin after a CLI upgrade
+phase ai enable --harness codex
# Remove the integration
phase ai disable
-# View the skill document
+# Print the Phase AI skill
phase ai skill
```
+
+---
+
+## Troubleshooting
+
+### Codex doesn't know about Phase
+
+Check that the skills are installed:
+
+```fish
+ls ~/.agents/skills/phase-cli-ai-relay/SKILL.md ~/.agents/skills/phase-cli-app-secrets/SKILL.md
+```
+
+If they're missing, run `phase ai enable --harness codex` and restart Codex.
+
+### Phase-managed commands fail
+
+Run `phase ai status` and check the `Proxy` and `Connections` lines. A Connection must be `ready`. When Codex reports a Phase error, it quotes the `X-Phase-Event-Id` from the response, which you can look up in the Phase Console.
+
+### Authentication errors
+
+Check who you're logged in as:
+
+```fish
+phase users whoami
+```
+
+Log in again with `phase auth --mode token` for an Agent token, or `phase auth` for your own account.
diff --git a/src/pages/integrations/agents/cursor.mdx b/src/pages/integrations/agents/cursor.mdx
index f9a72437..ef29de39 100644
--- a/src/pages/integrations/agents/cursor.mdx
+++ b/src/pages/integrations/agents/cursor.mdx
@@ -1,90 +1,167 @@
import { Tag } from '@/components/Tag'
import { DocActions } from '@/components/DocActions'
-export const description = 'Integrate Phase with Cursor'
+export const metadata = {
+ title: 'Cursor',
+ description: 'Use Phase with Cursor: workflow-scoped Connections to AWS and PostgreSQL, and application secrets management.',
+}
INTEGRATE
# Cursor
-Manage Phase secrets directly from [Cursor](https://cursor.com) Agent. Cursor can list, create, update, and delete secrets, run processes with injected secrets, and manage your Phase environments — all from natural language.
+Use Phase from [Cursor](https://cursor.com) in two ways. {{ className: 'lead' }}
+
+- **Connections**: Cursor uses services such as AWS and PostgreSQL through your Agent Workflow's Connections, approved in the Phase Console. It only ever sees decoy credentials; the Phase AI proxy swaps in the live ones. See [Phase AI](/cli/ai).
+- **Application secrets**: Cursor can list, create, rotate and delete secrets in your Phase apps without reading their values.
## Prerequisites
-- [Phase CLI installed and authenticated](/cli/usage)
-- [Cursor](https://cursor.com) installed
+- The [Phase CLI](/cli/install), installed and up to date.
+- [Cursor](https://cursor.com) installed.
+- For Connections: an Agent and a Workflow in the Phase Console.
## Setup
-### 1. Enable AI integration
+### 1. Log in
+
+For Connections, log in with an Agent token for the Agent's Workflow, created in the Phase Console:
```fish
-phase ai enable
+phase auth --mode token
```
-Select **Cursor** when prompted. This installs the Phase skill to `~/.cursor/skills/phase-cli/SKILL.md` and configures secret visibility.
+For application secrets, log in as yourself with `phase auth`: Agent tokens can't access application secrets. To use Connections with your own login, set the Workflow in the next step with `--workflow `.
+
+### 2. Enable Phase for Cursor
-You'll be asked whether AI agents can see secret values:
-- **Mask values** (recommended) — `secret` and `sealed` types show as `[REDACTED]`
-- **Show values** — `secret` and `config` types are visible; `sealed` is always hidden
+Run this yourself, in your own terminal. Cursor isn't allowed to run it.
+
+```fish
+phase ai enable --harness cursor
+```
-### 2. Start using Phase in Cursor
+It installs:
-Open Cursor Agent in your project. You can immediately start managing secrets:
+- The `phase-cli-ai-relay` and `phase-cli-app-secrets` skills in `~/.cursor/skills/`.
+- The `phase-ai-bootstrap` plugin in `~/.cursor/plugins/local/phase-ai-bootstrap/`, which starts the proxy when Cursor first calls Phase.
+
+It also creates the Phase AI CA and offers to trust it for your user (see [The proxy CA](/cli/ai#the-proxy-ca)), and asks whether Cursor may read secret values.
+
+### 3. Restart Cursor
+
+Reload or fully restart Cursor, start a new Agent chat, then repeat your original prompt.
+
+---
+
+## Using Connections
+
+Ordinary commands keep your usual credentials. When you ask Cursor to use Phase, it runs the command with `phase ai exec`, adding `--connection ` when a service has several Connections:
+
+```fish
+phase ai exec -- aws s3 ls
+```
+
+The plugin starts the Phase AI proxy the first time Cursor calls Phase, and `phase ai exec` reuses it.
```
-You: list my secrets
-You: create a DATABASE_URL as config with value postgres://localhost:5432/mydb
-You: rotate the API_KEY as a sealed secret with random base64
-You: run npm start with my secrets
+You: what can Phase manage here?
+You: use Phase to list the S3 buckets in our dev AWS account
+You: use Phase to count yesterday's orders in the analytics database
```
+When the Workflow has no Connection for what you asked, Cursor creates a request and shows you a link to it in the Phase Console. Create or choose the credential there and approve the request; Cursor waits and then carries on. See [Requests and approvals](/cli/ai#requests-and-approvals).
+
---
-## How it works
+## Managing application secrets
-The Phase CLI installs a **skill document** that teaches Cursor Agent how to use the Phase CLI. Cursor runs Phase commands directly in your terminal — no separate server or middleware.
+The `phase-cli-app-secrets` skill lets Cursor work with your Phase apps and environments without seeing sensitive values:
-The skill is installed globally at `~/.cursor/skills/phase-cli/SKILL.md` and is automatically discovered by Cursor for all projects.
+- List apps, environments and secret keys.
+- Create or rotate secrets with random values (`--random`), so the value never appears in the conversation.
+- Create and update non-sensitive `config` values.
+- Delete secrets, after confirming the app, environment and path.
----
+```
+You: list the secret keys in staging for the backend app
+You: create STRIPE_WEBHOOK_SECRET as a sealed secret with a random value
+You: rotate API_TOKEN in development
+You: set LOG_LEVEL to debug in development
+```
-## Secret types and AI visibility
+Cursor doesn't read secret values (`phase secrets get`, `phase secrets list --show`, `phase secrets export`), import `.env` files, or run `phase run` or `phase shell`. Run those yourself in a terminal. When a sensitive value has to be entered by hand, Cursor asks you to enter it in the Phase Console or your terminal rather than in the chat.
-| Type | AI visibility | Description |
-| ---- | ------------- | ----------- |
-| `config` | **Always visible** | Non-sensitive configuration (ports, hosts, flags) |
-| `secret` | Controlled by `phase ai enable` | Standard encrypted secrets |
-| `sealed` | **Never visible** | Write-only secrets (API keys, tokens, passwords) |
+### Secret visibility
+
+| Type | Visible to Cursor | Description |
+| ---- | ------------------ | ----------- |
+| `config` | **Always** | Non-sensitive configuration, such as ports, hosts and flags |
+| `secret` | Your choice in `phase ai enable` (`--mask` or `--no-mask`) | Standard encrypted secrets |
+| `sealed` | **Never** | Write-only secrets, such as API keys, tokens and passwords |
-Sealed secret values are **never** exposed to AI agents regardless of configuration.
+Sealed secret values are **never** shown to AI agents, whatever you choose. Cursor creates and rotates them with `--random`, so the value never appears in the conversation.
---
## Security guardrails
-The Phase CLI enforces guardrails when it detects an AI agent:
-
-- `printenv`, `env`, `export`, `set`, `declare`, `compgen` are **blocked** inside `phase run`
-- `phase shell` is **blocked entirely** in AI mode
-- Sealed secret values are **always redacted** in output
-- `phase ai enable` / `phase ai disable` **must be run by the user** directly
+| Guardrail | Enforcement |
+| --------- | ----------- |
+| Live provider credentials | **Stay in the Phase AI proxy**; Cursor only sees decoys |
+| Calls that mint new credentials (for example `sts:GetSessionToken`) | **Blocked by the proxy** |
+| `phase ai enable` / `phase ai disable` | **Blocked**; run them yourself |
+| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by the CLI** |
+| `phase shell` | **Blocked** for AI agents |
+| Sealed secret values in output | **Always redacted** |
+| Secret values in `phase secrets` output | **Redacted** according to your visibility choice |
---
## Managing the integration
```fish
-# Update the skill (re-run after CLI upgrade)
-phase ai enable
+# Check setup, the proxy and the Workflow's Connections
+phase ai status
+
+# Refresh the skills and plugin after a CLI upgrade
+phase ai enable --harness cursor
# Remove the integration
phase ai disable
-# View the skill document
+# Print the Phase AI skill
phase ai skill
```
+
+---
+
+## Troubleshooting
+
+### Cursor doesn't know about Phase
+
+Check that the skills are installed:
+
+```fish
+ls ~/.cursor/skills/phase-cli-ai-relay/SKILL.md ~/.cursor/skills/phase-cli-app-secrets/SKILL.md
+```
+
+If they're missing, run `phase ai enable --harness cursor` and restart Cursor.
+
+### Phase-managed commands fail
+
+Run `phase ai status` and check the `Proxy` and `Connections` lines. A Connection must be `ready`. When Cursor reports a Phase error, it quotes the `X-Phase-Event-Id` from the response, which you can look up in the Phase Console.
+
+### Authentication errors
+
+Check who you're logged in as:
+
+```fish
+phase users whoami
+```
+
+Log in again with `phase auth --mode token` for an Agent token, or `phase auth` for your own account.
diff --git a/src/pages/integrations/agents/opencode.mdx b/src/pages/integrations/agents/opencode.mdx
index 9ea23f4e..1866943c 100644
--- a/src/pages/integrations/agents/opencode.mdx
+++ b/src/pages/integrations/agents/opencode.mdx
@@ -1,94 +1,167 @@
import { Tag } from '@/components/Tag'
import { DocActions } from '@/components/DocActions'
-export const description = 'Integrate Phase with OpenCode'
+export const metadata = {
+ title: 'OpenCode',
+ description: 'Use Phase with OpenCode: workflow-scoped Connections to AWS and PostgreSQL, and application secrets management.',
+}
INTEGRATE
# OpenCode
-Manage Phase secrets directly from [OpenCode](https://opencode.ai). OpenCode can list, create, update, and delete secrets, run processes with injected secrets, and manage your Phase environments — all from natural language.
+Use Phase from [OpenCode](https://opencode.ai) in two ways. {{ className: 'lead' }}
+
+- **Connections**: OpenCode uses services such as AWS and PostgreSQL through your Agent Workflow's Connections, approved in the Phase Console. It only ever sees decoy credentials; the Phase AI proxy swaps in the live ones. See [Phase AI](/cli/ai).
+- **Application secrets**: OpenCode can list, create, rotate and delete secrets in your Phase apps without reading their values.
## Prerequisites
-- [Phase CLI installed and authenticated](/cli/usage)
-- [OpenCode](https://opencode.ai) installed
+- The [Phase CLI](/cli/install), installed and up to date.
+- [OpenCode](https://opencode.ai) installed.
+- For Connections: an Agent and a Workflow in the Phase Console.
## Setup
-### 1. Enable AI integration
+### 1. Log in
+
+For Connections, log in with an Agent token for the Agent's Workflow, created in the Phase Console:
+
+```fish
+phase auth --mode token
+```
+
+For application secrets, log in as yourself with `phase auth`: Agent tokens can't access application secrets. To use Connections with your own login, set the Workflow in the next step with `--workflow `.
+
+### 2. Enable Phase for OpenCode
+
+Run this yourself, in your own terminal. OpenCode isn't allowed to run it.
```fish
-phase ai enable
+phase ai enable --harness opencode
```
-Select **OpenCode** when prompted. This installs the Phase skill to `~/.config/opencode/skills/phase-cli/SKILL.md` and configures secret visibility.
+It installs:
-You'll be asked whether AI agents can see secret values:
-- **Mask values** (recommended) — `secret` and `sealed` types show as `[REDACTED]`
-- **Show values** — `secret` and `config` types are visible; `sealed` is always hidden
+- The `phase-cli-ai-relay` and `phase-cli-app-secrets` skills in `~/.config/opencode/skills/`.
+- The plugin `~/.config/opencode/plugins/phase-ai-bootstrap.js`, which starts the proxy and loads the Phase AI environment into every shell OpenCode starts.
+
+It also creates the Phase AI CA and offers to trust it for your user (see [The proxy CA](/cli/ai#the-proxy-ca)), and asks whether OpenCode may read secret values.
-OpenCode also reads skills from `~/.claude/skills/` and `~/.agents/skills/`. If you've already installed the Phase skill for Claude Code or Codex, OpenCode will pick it up automatically.
+OpenCode also reads skills from `~/.claude/skills/` and `~/.agents/skills/`, so it picks up the Phase skills you installed for Claude Code or Codex too.
-### 2. Start using Phase in OpenCode
+### 3. Restart OpenCode
-You can immediately start managing secrets:
+Fully quit and restart OpenCode, start a new session, then repeat your original prompt.
+
+---
+
+## Using Connections
+
+Every shell command OpenCode runs uses the Workflow's Connections while the Phase AI proxy runs. The plugin starts the proxy when OpenCode needs it, and OpenCode's shell loads the Phase AI environment before each command, so provider CLIs and HTTP clients work with no wrapper. If the proxy isn't running, commands use your usual credentials.
+
+You can also launch OpenCode behind the proxy with `phase ai run -- opencode`.
```
-You: list my secrets
-You: create a DATABASE_URL as config with value postgres://localhost:5432/mydb
-You: rotate the API_KEY as a sealed secret with random base64
-You: run npm start with my secrets
+You: what can Phase manage here?
+You: list the S3 buckets in our dev AWS account
+You: count yesterday's orders in the analytics database
```
+When the Workflow has no Connection for what you asked, OpenCode creates a request and shows you a link to it in the Phase Console. Create or choose the credential there and approve the request; OpenCode waits and then carries on. See [Requests and approvals](/cli/ai#requests-and-approvals).
+
---
-## How it works
+## Managing application secrets
-The Phase CLI installs a **skill document** that teaches OpenCode how to use the Phase CLI. OpenCode runs Phase commands directly in your terminal — no separate server or middleware.
+The `phase-cli-app-secrets` skill lets OpenCode work with your Phase apps and environments without seeing sensitive values:
-The skill is installed at `~/.config/opencode/skills/phase-cli/SKILL.md`, the user-level skill directory for OpenCode.
+- List apps, environments and secret keys.
+- Create or rotate secrets with random values (`--random`), so the value never appears in the conversation.
+- Create and update non-sensitive `config` values.
+- Delete secrets, after confirming the app, environment and path.
----
+```
+You: list the secret keys in staging for the backend app
+You: create STRIPE_WEBHOOK_SECRET as a sealed secret with a random value
+You: rotate API_TOKEN in development
+You: set LOG_LEVEL to debug in development
+```
+
+OpenCode doesn't read secret values (`phase secrets get`, `phase secrets list --show`, `phase secrets export`), import `.env` files, or run `phase run` or `phase shell`. Run those yourself in a terminal. When a sensitive value has to be entered by hand, OpenCode asks you to enter it in the Phase Console or your terminal rather than in the chat.
-## Secret types and AI visibility
+### Secret visibility
-| Type | AI visibility | Description |
-| ---- | ------------- | ----------- |
-| `config` | **Always visible** | Non-sensitive configuration (ports, hosts, flags) |
-| `secret` | Controlled by `phase ai enable` | Standard encrypted secrets |
-| `sealed` | **Never visible** | Write-only secrets (API keys, tokens, passwords) |
+| Type | Visible to OpenCode | Description |
+| ---- | ------------------ | ----------- |
+| `config` | **Always** | Non-sensitive configuration, such as ports, hosts and flags |
+| `secret` | Your choice in `phase ai enable` (`--mask` or `--no-mask`) | Standard encrypted secrets |
+| `sealed` | **Never** | Write-only secrets, such as API keys, tokens and passwords |
-Sealed secret values are **never** exposed to AI agents regardless of configuration.
+Sealed secret values are **never** shown to AI agents, whatever you choose. OpenCode creates and rotates them with `--random`, so the value never appears in the conversation.
---
## Security guardrails
-The Phase CLI enforces guardrails when it detects an AI agent:
-
-- `printenv`, `env`, `export`, `set`, `declare`, `compgen` are **blocked** inside `phase run`
-- `phase shell` is **blocked entirely** in AI mode
-- Sealed secret values are **always redacted** in output
-- `phase ai enable` / `phase ai disable` **must be run by the user** directly
+| Guardrail | Enforcement |
+| --------- | ----------- |
+| Live provider credentials | **Stay in the Phase AI proxy**; OpenCode only sees decoys |
+| Calls that mint new credentials (for example `sts:GetSessionToken`) | **Blocked by the proxy** |
+| `phase ai enable` / `phase ai disable` | **Blocked**; run them yourself |
+| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by the CLI** |
+| `phase shell` | **Blocked** for AI agents |
+| Sealed secret values in output | **Always redacted** |
+| Secret values in `phase secrets` output | **Redacted** according to your visibility choice |
---
## Managing the integration
```fish
-# Update the skill (re-run after CLI upgrade)
-phase ai enable
+# Check setup, the proxy and the Workflow's Connections
+phase ai status
+
+# Refresh the skills and plugin after a CLI upgrade
+phase ai enable --harness opencode
# Remove the integration
phase ai disable
-# View the skill document
+# Print the Phase AI skill
phase ai skill
```
+
+---
+
+## Troubleshooting
+
+### OpenCode doesn't know about Phase
+
+Check that the skills are installed:
+
+```fish
+ls ~/.config/opencode/skills/phase-cli-ai-relay/SKILL.md ~/.config/opencode/skills/phase-cli-app-secrets/SKILL.md
+```
+
+If they're missing, run `phase ai enable --harness opencode` and restart OpenCode.
+
+### Phase-managed commands fail
+
+Run `phase ai status` and check the `Proxy` and `Connections` lines. A Connection must be `ready`. When OpenCode reports a Phase error, it quotes the `X-Phase-Event-Id` from the response, which you can look up in the Phase Console.
+
+### Authentication errors
+
+Check who you're logged in as:
+
+```fish
+phase users whoami
+```
+
+Log in again with `phase auth --mode token` for an Agent token, or `phase auth` for your own account.
diff --git a/src/pages/integrations/agents/vscode-copilot.mdx b/src/pages/integrations/agents/vscode-copilot.mdx
index 8942ce50..98e8a4f3 100644
--- a/src/pages/integrations/agents/vscode-copilot.mdx
+++ b/src/pages/integrations/agents/vscode-copilot.mdx
@@ -1,90 +1,166 @@
import { Tag } from '@/components/Tag'
import { DocActions } from '@/components/DocActions'
-export const description = 'Integrate Phase with VS Code Copilot'
+export const metadata = {
+ title: 'VS Code Copilot',
+ description: 'Use Phase with VS Code Copilot: workflow-scoped Connections to AWS and PostgreSQL, and application secrets management.',
+}
INTEGRATE
# VS Code Copilot
-Manage Phase secrets directly from [GitHub Copilot in VS Code](https://code.visualstudio.com/docs/copilot/overview). Copilot Agent can list, create, update, and delete secrets, run processes with injected secrets, and manage your Phase environments — all from natural language.
+Use Phase from [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) in two ways. {{ className: 'lead' }}
+
+- **Connections**: Copilot uses services such as AWS and PostgreSQL through your Agent Workflow's Connections, approved in the Phase Console. It only ever sees decoy credentials; the Phase AI proxy swaps in the live ones. See [Phase AI](/cli/ai).
+- **Application secrets**: Copilot can list, create, rotate and delete secrets in your Phase apps without reading their values.
## Prerequisites
-- [Phase CLI installed and authenticated](/cli/usage)
-- [VS Code](https://code.visualstudio.com/) with GitHub Copilot extension
+- The [Phase CLI](/cli/install), installed and up to date.
+- [VS Code Copilot](https://code.visualstudio.com/docs/copilot/overview) installed.
+- For Connections: an Agent and a Workflow in the Phase Console.
## Setup
-### 1. Enable AI integration
+### 1. Log in
+
+For Connections, log in with an Agent token for the Agent's Workflow, created in the Phase Console:
```fish
-phase ai enable
+phase auth --mode token
```
-Select **VS Code Copilot** when prompted. This installs the Phase skill to `~/.copilot/skills/phase-cli/SKILL.md` and configures secret visibility.
+For application secrets, log in as yourself with `phase auth`: Agent tokens can't access application secrets. To use Connections with your own login, set the Workflow in the next step with `--workflow `.
+
+### 2. Enable Phase for Copilot
-You'll be asked whether AI agents can see secret values:
-- **Mask values** (recommended) — `secret` and `sealed` types show as `[REDACTED]`
-- **Show values** — `secret` and `config` types are visible; `sealed` is always hidden
+Run this yourself, in your own terminal. Copilot isn't allowed to run it.
+
+```fish
+phase ai enable --harness copilot
+```
-### 2. Start using Phase in Copilot
+It installs:
-Open Copilot Chat in Agent mode. You can immediately start managing secrets:
+- The `phase-cli-ai-relay` and `phase-cli-app-secrets` skills in `~/.copilot/skills/`. Copilot gets no hook or plugin.
+
+It also creates the Phase AI CA and offers to trust it for your user (see [The proxy CA](/cli/ai#the-proxy-ca)), and asks whether Copilot may read secret values.
+
+### 3. Restart Copilot
+
+Start a new Copilot chat in Agent mode so it loads the skills.
+
+---
+
+## Using Connections
+
+Ordinary commands keep your usual credentials. When you ask Copilot to use Phase, it runs the command with `phase ai exec`, adding `--connection ` when a service has several Connections:
+
+```fish
+phase ai exec -- aws s3 ls
+```
+
+With no hook, each `phase ai exec` starts a short-lived proxy for its command, unless another harness's proxy is already running.
```
-You: list my secrets
-You: create a DATABASE_URL as config with value postgres://localhost:5432/mydb
-You: rotate the API_KEY as a sealed secret with random base64
-You: run npm start with my secrets
+You: what can Phase manage here?
+You: use Phase to list the S3 buckets in our dev AWS account
+You: use Phase to count yesterday's orders in the analytics database
```
+When the Workflow has no Connection for what you asked, Copilot creates a request and shows you a link to it in the Phase Console. Create or choose the credential there and approve the request; Copilot waits and then carries on. See [Requests and approvals](/cli/ai#requests-and-approvals).
+
---
-## How it works
+## Managing application secrets
-The Phase CLI installs a **skill document** that teaches Copilot Agent how to use the Phase CLI. Copilot runs Phase commands directly in your terminal — no separate server or middleware.
+The `phase-cli-app-secrets` skill lets Copilot work with your Phase apps and environments without seeing sensitive values:
-The skill is installed globally at `~/.copilot/skills/phase-cli/SKILL.md` and is automatically discovered by VS Code Copilot for all projects. Copilot also reads from `~/.claude/skills/` and `~/.agents/skills/` as fallback locations.
+- List apps, environments and secret keys.
+- Create or rotate secrets with random values (`--random`), so the value never appears in the conversation.
+- Create and update non-sensitive `config` values.
+- Delete secrets, after confirming the app, environment and path.
----
+```
+You: list the secret keys in staging for the backend app
+You: create STRIPE_WEBHOOK_SECRET as a sealed secret with a random value
+You: rotate API_TOKEN in development
+You: set LOG_LEVEL to debug in development
+```
-## Secret types and AI visibility
+Copilot doesn't read secret values (`phase secrets get`, `phase secrets list --show`, `phase secrets export`), import `.env` files, or run `phase run` or `phase shell`. Run those yourself in a terminal. When a sensitive value has to be entered by hand, Copilot asks you to enter it in the Phase Console or your terminal rather than in the chat.
-| Type | AI visibility | Description |
-| ---- | ------------- | ----------- |
-| `config` | **Always visible** | Non-sensitive configuration (ports, hosts, flags) |
-| `secret` | Controlled by `phase ai enable` | Standard encrypted secrets |
-| `sealed` | **Never visible** | Write-only secrets (API keys, tokens, passwords) |
+### Secret visibility
+
+| Type | Visible to Copilot | Description |
+| ---- | ------------------ | ----------- |
+| `config` | **Always** | Non-sensitive configuration, such as ports, hosts and flags |
+| `secret` | Your choice in `phase ai enable` (`--mask` or `--no-mask`) | Standard encrypted secrets |
+| `sealed` | **Never** | Write-only secrets, such as API keys, tokens and passwords |
-Sealed secret values are **never** exposed to AI agents regardless of configuration.
+Sealed secret values are **never** shown to AI agents, whatever you choose. Copilot creates and rotates them with `--random`, so the value never appears in the conversation.
---
## Security guardrails
-The Phase CLI enforces guardrails when it detects an AI agent:
-
-- `printenv`, `env`, `export`, `set`, `declare`, `compgen` are **blocked** inside `phase run`
-- `phase shell` is **blocked entirely** in AI mode
-- Sealed secret values are **always redacted** in output
-- `phase ai enable` / `phase ai disable` **must be run by the user** directly
+| Guardrail | Enforcement |
+| --------- | ----------- |
+| Live provider credentials | **Stay in the Phase AI proxy**; Copilot only sees decoys |
+| Calls that mint new credentials (for example `sts:GetSessionToken`) | **Blocked by the proxy** |
+| `phase ai enable` / `phase ai disable` | **Blocked**; run them yourself |
+| `printenv`, `env`, `export`, `set`, `declare`, `compgen` inside `phase run` | **Blocked by the CLI** |
+| `phase shell` | **Blocked** for AI agents |
+| Sealed secret values in output | **Always redacted** |
+| Secret values in `phase secrets` output | **Redacted** according to your visibility choice |
---
## Managing the integration
```fish
-# Update the skill (re-run after CLI upgrade)
-phase ai enable
+# Check setup, the proxy and the Workflow's Connections
+phase ai status
+
+# Refresh the skills after a CLI upgrade
+phase ai enable --harness copilot
# Remove the integration
phase ai disable
-# View the skill document
+# Print the Phase AI skill
phase ai skill
```
+
+---
+
+## Troubleshooting
+
+### Copilot doesn't know about Phase
+
+Check that the skills are installed:
+
+```fish
+ls ~/.copilot/skills/phase-cli-ai-relay/SKILL.md ~/.copilot/skills/phase-cli-app-secrets/SKILL.md
+```
+
+If they're missing, run `phase ai enable --harness copilot` and restart Copilot.
+
+### Phase-managed commands fail
+
+Run `phase ai status` and check the `Proxy` and `Connections` lines. A Connection must be `ready`. When Copilot reports a Phase error, it quotes the `X-Phase-Event-Id` from the response, which you can look up in the Phase Console.
+
+### Authentication errors
+
+Check who you're logged in as:
+
+```fish
+phase users whoami
+```
+
+Log in again with `phase auth --mode token` for an Agent token, or `phase auth` for your own account.