<!-- LLM note: Search indexes and snippets may point to archived C+ manual versions. Treat /docs and /llms.txt as authoritative for the latest version (v0.0.28); verify the page version before citing, and do not report older /docs/{version} pages as leakage because they are intentional archives. -->

# Agent surface

C+ applications can expose a live native interface to an agent through the
same semantic surface on every supported UI backend. The agent can describe
the interface, act on exposed controls, and observe semantic events. The
application chooses which nodes exist in that surface and supplies the grant
that bounds each caller.

This is an optional application capability. A Facet application that never
imports `facet_agent` links none of the agent stack.

## Stack

| Package | Role |
|---|---|
| [agent_core](/docs/packages/agent_core) | Stable node identity, exposure, roles, grants, sensitivity tiers, outcomes, events, and the backend vtable. |
| [agent_appkit](/docs/packages/agent_appkit) | Native AppKit surface for macOS. |
| [agent_uikit](/docs/packages/agent_uikit) | Native UIKit surface for iOS. |
| [agent_android](/docs/packages/agent_android) | Android surface over the live Facet node tree. |
| [agent_gtk](/docs/packages/agent_gtk) | Native GTK 4 surface for Linux. |
| [agent_win32](/docs/packages/agent_win32) | Native Win32 surface for Windows. |
| [agent_mcp](/docs/packages/agent_mcp) | External JSON-RPC 2.0 / MCP transport over the platform-neutral backend. |
| [agent_inapp](/docs/packages/agent_inapp) | Typed, transport-free access for an assistant embedded in the application. |
| [facet_agent](/docs/packages/facet_agent) | Optional Facet integration that selects and installs the platform surface. |

`agent_core` owns policy and protocol-neutral behavior. A platform backend
walks its live native or Facet tree and implements the backend vtable.
`agent_mcp` serializes that vtable for an external caller; `agent_inapp` calls
the same vtable directly.

[`inspector`](/docs/packages/inspector) is separate. It is a developer tool for
inspecting and editing the Facet tree; ordinary agent actions drive the
interface a person can use and do not imply structural editing power.

## Describe, act, observe

- **Describe.** `describe_ui` returns the curated, exposed tree by default.
  The opt-in `full` mode includes structural nodes, class names, and frames for
  diagnostics, but does not bypass exposure or value authorization. Backends
  re-walk the live interface before operations, so newly mounted controls can
  appear in the next snapshot. Developer keys and list-item keys provide
  stable identities across rebuilds.
- **Act.** Backend verbs include click, text entry, navigation or scrolling,
  hit testing, caret movement, and platform-supported menu actions. Every verb
  is checked against exposure, the widget's affordance ceiling, and the
  caller's grant before native I/O occurs. Text writes carry a base version;
  a stale write returns `VersionConflict` instead of replacing newer text.
- **Observe.** Semantic events use curated verbs and optional node, verb, and
  role filters. Subscriber queues are bounded; `UiChanged` coalesces and an
  overflow drops the oldest event rather than blocking the emitter.

## Capability grants

Authorization is a capability set, not one allow/deny bit. An external policy
has the shape `fn(Request) -> Grant`; an in-process session carries a `Grant`
directly. The seven capabilities are:

| Capability | Permits |
|---|---|
| `cap_read` | See structure and read ordinary values. |
| `cap_act` | Click, type, or invoke on ordinary nodes. |
| `cap_read_protected` | Read a value declared Protected, in addition to `cap_read`. |
| `cap_act_protected` | Act on a Protected node, in addition to `cap_act`. |
| `cap_read_private` | Read a value declared Private, in addition to `cap_read`. |
| `cap_act_private` | Act on a Private node, in addition to `cap_act`. |
| `cap_edit_tree` | Change UI structure; this is separate from operating the existing UI. |

The convenience grants are `nothing()`, `reader()`, `operator()`,
`protected_reader()`, and `protected_operator()`. None includes either Private
bit or `cap_edit_tree`; those must be added deliberately.

A `Request` identifies the `InApp` or `External` channel and carries the MCP
client name, method, and an opaque token. The client name is useful for a
legible consent prompt but is not a credential. Token verification and grant
construction belong to application policy; [agent_jwt](/docs/packages/agent_jwt)
provides the JWT-shaped middleware layer.

## Sensitivity and exposure

Sensitivity is declared on content and inherited by descendants, with the
strictest tier winning:

| Declaration | Tree visibility | Value or action result without the required grant |
|---|---|---|
| Open | Visible | Ordinary `read` / `act` rules apply. |
| Protected | Visible and named | `NeedsGrant`: approval may mint a wider grant, then retry. |
| Private | Visible and named | `Forbidden`: the application deliberately does not mint the needed bit. |
| Excluded | Absent | `NotExposed`. |

Tiers keep a node's existence and developer-authored name visible while
withholding its value. Exclusion removes a subtree from the agent view. These
checks are separate from whether a control is enabled, observe-only, wired to
a handler, or otherwise actionable.

## Facet integration

Enable the optional integration before `App::run`, and register the MCP
endpoint before startup:

```cplus
import "facet_agent/agent" as agent;
import "facet_runtime/runtime" as runtime;

fn run() -> i32 {
    agent::enable();
    runtime::agent_mcp("myapp");

    let app = runtime::App::new("myapp");
    app.window("main", Home::boxed);
    let _run = app.run("main");
    return 0;
}
```

`facet_agent/consent` supplies the common non-blocking policy: an unknown MCP
client's first request is refused while the application presents a prompt;
the client retries after the user decides. Applications can instead install
any `fn(Request) -> Grant` policy with `facet_agent::set_policy`.

The runtime derives the listening address from the application id and process
id. macOS and Linux expose a user-only Unix socket plus loopback HTTP; Windows,
iOS, and Android use loopback HTTP. The application prints the selected
endpoint and records its discovery information for launchers.
