<!-- 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.25); verify the page version before citing, and do not report older /docs/{version} pages as leakage because they are intentional archives. -->

# agent_win32

The Windows backend for the [agent surface](/docs/agent-surface): it binds the
framework-neutral [agent_core](/docs/packages/agent_core) identity and
authorization model to a live Win32 window. It is the sibling of
[agent_appkit](/docs/packages/agent_appkit), and reuses `agent_core` unchanged —
only this thin bridge is Windows-specific.

- **`open(window)`** walks the live HWND hierarchy into a `Surface` — the
  controllable model an agent sees. The walk is a DFS over
  `GetWindow(GW_CHILD / GW_HWNDNEXT)`.
- **`describe()`** returns a live snapshot of the nodes (`Vec[UiNode]`). A node
  is *exposed* — part of the curated surface — by giving it an agent id with
  `set_agent_id`. Untagged windows are still walked for tree completeness but are
  `NotExposed`, so actions on them are refused.
- **Authorized actions** — `click`, `set_text`, and `focus` run through the
  `agent_core` authorization brain. Text edits use optimistic-concurrency
  versioning, so a stale edit is rejected with `VersionConflict`.
- **Events** — `emit` translates a fired control into an `agent_core` verb and
  offers it to a `Subscriber`.
- **No GUI-toolkit dependency.** Introspection is plain `user32` `extern fn`
  calls (`GetWindow` / `GetClassNameA` / `GetWindowTextA` / …), so it can
  describe *any* HWND tree, including one built with raw Win32 or any toolkit.

## Curate, snapshot, act

Tag the controls the agent may see and touch, snapshot the window, then act.
The agent id is a stable NUL-terminated string literal — only its address is
held (via `SetPropA`), so pass a literal with static lifetime.

```cplus
import "agent_win32/agent_win32" as agent;
import "agent_core/surface" as surface;

// 1. Curate: tag the controls the agent may see / act on.
agent::set_agent_id(button_hwnd, #str_ptr("btn_login\0"));
agent::set_agent_id(field_hwnd,  #str_ptr("user_field\0"));

// 2. Snapshot the window (the READ path).
let surf: agent::Surface = agent::open(window_hwnd);
let nodes: vec::Vec[agent::UiNode] = surf.describe();
//   each UiNode = { id, role, class_name, frame, is_hidden, text,
//                   actionable, parent }

// 3. Act (the WRITE path) — each call is authorized by agent_core first.
let _ = surf.click("btn_login");                 // -> surface::Outcome
let v  = surf.text_version("user_field");
let _ = surf.set_text("user_field", "alice", v); // optimistic concurrency
```

`describe()` reads each node's frame, hidden state, and caption *now*, so the
snapshot reflects the result of a preceding `set_text`. `parent` indexes back
into the returned `Vec[UiNode]` (`None` for the window root) so the flat list
reconstructs the tree.

## The write path

Every mutation resolves the agent id to a node and asks `agent_core` first; the
real I/O runs only on `Allowed`. The result is a `surface::Outcome`
(`Allowed` / `NotFound` / `NotExposed` / `NotActionable` / `VersionConflict`).

- **`click`** — `authorize_action`, then `SendMessage(BM_CLICK)`.
- **`set_text`** — `authorize_text_write` with the version the agent last read,
  then `SetWindowTextA` and a version bump. Pass `text_version(id)` as the base
  version; a racing edit yields `VersionConflict`.
- **`focus`** — `authorize_read`, then `SetFocus`. This is the Win32 analogue of
  scroll-to-visible: focusing a control scrolls it into view in a scrollable
  parent.

```cplus
let v: u64 = surf.text_version("user_field");
match surf.set_text("user_field", "alice", v) {
    surface::Outcome::Allowed         => { /* applied */ }
    surface::Outcome::VersionConflict => { /* re-read and retry */ }
    _                                 => { /* refused */ }
}
```

`set_text` mutates the version state, so its receiver is `ref this`; call it on
a `var` surface.

## Role classification

The walk maps each window to the curated `agent_core::Role` by class name (plus
style bits): `Edit` → `Input`, `Static` → `Text`, `ListBox` / `ComboBox` →
`List`, and the single `Button` class splits by the low nibble of the window
style into push/checkbox/radio (`Button`) versus group boxes (`Group`). The
window root itself is role `Window`.

## Platform notes

- **Windows only.** The package links `user32` (declared in `Cplus.toml`), which
  ships with Windows and is on the linker's default search path. See
  [targets](/docs/targets) for cross-compilation.
- **No main-thread marshaling helper.** Unlike the AppKit backend, Win32 needs
  none: a cross-thread `SendMessage` is delivered on the window's owning thread
  by the OS, so the gated actions are direct sends.
- **Flatter tree.** Win32 controls are direct children of the window, so the
  child-window depth tracked by the DFS is shallow in practice.

## Serving the surface

`mcp_backend()` returns a backend-neutral `agent_core::backend::Backend` vtable
(`describe` / `click` / `set_text` / `navigate`, where navigate is `focus`),
widening the integer Win32 rect to the f64 `Rect` the neutral node list uses.
Pair it with [agent_mcp](/docs/packages/agent_mcp) to expose the surface to an
external agent. To describe a C+-built GUI, see [facet](/docs/packages/facet) and
[builder blocks](/docs/builder-blocks).
