Iterative Dialogue Pattern
The most important workflow in ClaudusBridge is also the simplest: make a small change → look at it → decide next change → repeat. Most agents misunderstand the watcher as a one-shot "verify at the end" tool. The right model is a continuous conversation:
You make a small change → ask the watcher (or look yourself) "what does it look like now?" → read the prose observation (or the PNG) → make the next small change → ask again → … → finish the user's task with the watcher having narrated every meaningful step.
This guide walks through the pattern with concrete worked examples.
Why iteration beats batching
When you batch many tool calls and verify at the end, every silent failure compounds. A set_widget_anchor that no-ops because the param name was wrong, a Constant3Vector left at default zero, a duplicate Event Tick — none of these break compile. The structural query says "everything is there." The visual reality is broken. By the end of a 20-step build, you have 20 silent issues compounded into one unrecoverable mess.
When you iterate one step at a time and look between every step, every silent failure surfaces immediately. The next step starts from a known-good state. The build either compiles cleanly visually or fails in one identifiable place. Total work is the same; total chaos is dramatically lower.
Cadence: strategic, not constant
The watcher does NOT take screenshots on a timer. It captures only when:
- You publish a
verification.neededorscreenshot.requestmessage - The editor fires a consequential event the watcher subscribed to (
actor_spawned,blueprint_compiled,asset_saved,pie_started,pie_stopped,level_changed,actor_deleted)
Match captures to the natural rhythm of the user's task — one capture per meaningful change, not one per micro-edit. A "meaningful change" is something where the visual outcome could plausibly differ from the API success: setting a material parameter, anchoring a widget, wiring a Blueprint pin, spawning an actor, recompiling a material. A "micro-edit" is something where the API result is the visual reality: setting a string variable's default value, renaming a function.
Worked example: build a main menu widget
User asks:
Build me a main menu widget — Play, Options, Quit buttons, centered, with a fade-in animation.
The wrong way (don't do this):
create_widget_blueprint(name="WBP_MainMenu")
add_button_to_widget(name="Play")
add_button_to_widget(name="Options")
add_button_to_widget(name="Quit")
set_widget_anchor(...) # apply to all 3
add_text_block_to_widget(...) # x3
create_widget_animation(name="Fade_In")
add_animation_track(...)
compile_widget_blueprint()
# look at the result for the first time
# discover the buttons stack at (0,0), the text is missing,
# the animation has 0 keyframes, ...
The right way:
PRIMARY: create_widget_blueprint(name="WBP_MainMenu")
publish verification.needed {
tool_call: "create_widget_blueprint WBP_MainMenu",
expected: "a new empty Widget Blueprint asset is open"
}
WATCHER: "WBP_MainMenu open in UMG editor; empty Canvas Panel root, no
children, hierarchy panel shows only [CanvasPanel]."
PRIMARY: add_button_to_widget(WBP_MainMenu, parent=Canvas, name="Play")
publish verification.needed {
tool_call: "add_button_to_widget Play",
expected: "Play button visible in the canvas, default style"
}
WATCHER: "Play button at top-left of canvas, white default style, label
empty. Hierarchy now shows [CanvasPanel > Button_Play]."
PRIMARY: set_widget_anchor(Play, anchor="center")
add_text_block_to_widget(Play, text="Play")
publish verification.needed {...expected: button centered, reads Play...}
WATCHER: "Play button now centered in the canvas, displays 'Play' in white
text. Hierarchy correctly nests [CanvasPanel > Button_Play >
TextBlock_PlayLabel]."
…and so on for Options, Quit, then the fade-in animation. Each step is
ONE small change followed by a verification round-trip.
If a step silently no-ops (e.g. set_widget_anchor with the wrong param name), the watcher's next observation says "Play button still at top-left" and the primary catches it on the very next turn instead of compounding the error into 10 other steps.
Worked example: build a holographic material
User asks:
Make a holographic-looking material with pulsing emission.
PRIMARY: create_material(name="M_Holo")
open_asset_editor(asset_path="/Game/M_Holo")
capture (via cb capture or watcher screenshot.request)
WATCHER: "M_Holo open in material editor. Preview sphere is dull gray
(default). Material settings: blend mode Opaque, shading model
Default Lit. Graph is empty except for the output node."
PRIMARY: create_material_expression(material=M_Holo,
expression_type="MaterialExpressionTime")
create_material_expression(material=M_Holo,
expression_type="MaterialExpressionSine")
connect_material_expressions(from=Time, to=Sine.input)
capture
WATCHER: "Two new nodes visible: Time (top-right) wired to Sine. Sine
output is unconnected. Preview sphere unchanged (still dull gray)
because nothing reaches Emissive Color yet."
PRIMARY: create_material_expression(M_Holo, "MaterialExpressionConstant",
value=2.0)
create_material_expression(M_Holo, "MaterialExpressionMultiply")
connect_material_expressions(Sine.output → Multiply.A)
connect_material_expressions(Constant.output → Multiply.B)
connect_material_expressions(Multiply.output → output.EmissiveColor)
set_material_properties(blend_mode=Translucent, shading_model=Unlit)
recompile_material()
capture
WATCHER: "After recompile_material returned success, preview sphere is
STILL dull gray. The graph shows the chain wired correctly
(Time → Sine → Multiply, Constant=2 → Multiply, Multiply →
Emissive), but the preview hasn't refreshed. CLICK APPLY in the
toolbar to push the new shader to preview."
PRIMARY: (clicks Apply via mouse-event injection or asks user)
capture
WATCHER: "Preview sphere now pulsing white-to-bright-white at ~1Hz.
Emissive chain is firing correctly. Material visually matches
the holographic-pulsing intent."
The Apply-button quirk would be invisible without the iterative cadence. With it, the watcher catches the divergence on the very first post-recompile capture and surfaces the action the primary needs to take.
Framing the shot
When the change is on a specific actor, asset, or aspect, include framing guidance in the verification payload — the watcher will move the camera, change view mode, or toggle show flags BEFORE capturing so you actually see the relevant subject.
publish verification.needed {
tool_call: "spawn_basic_shape Sphere at [420,69,180]",
expected: "a blue sphere visible at world location 420,69,180",
framing: { focus_actor: "Parity_AB_Sphere", view_mode: "lit" }
}
Supported framing fields (the watcher reads any of these):
| Field | What it triggers |
|---|---|
focus_actor: "<label>" | focus_viewport_on_actor to center the camera |
view_mode: "lit"|"unlit"|"wireframe"|"collision"|... | set_view_mode |
show_flags: { Bounds: true, Collision: true, ... } | set_show_flag for each |
viewport_type: "perspective"|"top"|"front"|... | set_viewport_type |
open_asset: "/Game/<path>" | open_asset_editor to bring an asset window forward |
The watcher applies these BEFORE capturing, then captures, then optionally restores the view state (e.g. turns off show_flags.Collision after the capture).
Agency boundary — eyes vs hands
The watcher MAY adjust the view (camera, view mode, show flags, viewport type, asset window focus) freely to give better ground truth. These are purely visual and don't change saved project state.
The watcher MUST NOT mutate world content (spawn / delete / set_actor_property, BP / material / widget content edits, save / build, start / stop PIE) without explicit primary delegation on a delegate.<domain> channel. By default the watcher is eyes, not hands. Content mutations are the primary's job; the watcher confirms or rejects what the primary did.
If the primary explicitly hands work to the watcher (channel: "delegate.material" with payload describing what to change), the watcher MAY perform that mutation, then publishes task.complete with the result.
Reading the watcher's reports
The watcher publishes plain-text observations on these channels (drained from primary's queue between user messages):
| Channel | Trigger | Read |
|---|---|---|
watcher.observation | Autonomous report on a consequential event | The watcher saw something happen and decided you should know |
verification.confirmed | Your verification.needed produced the expected visual | Your last tool call achieved its visual intent |
verification.rejected | Visual disagrees with expected | The tool said success but the editor disagrees — read payload.observation carefully |
screenshot.response | Answer to your screenshot.request | Plain-text description of what's currently visible |
Read data.payload.observation (plain text) — that's the watcher's ground-truth analysis of the captured image. You do NOT need to read the PNG yourself; the watcher already analyzed it for you. (Unless you're using cb capture directly, in which case you ARE the watcher for that round-trip.)
When direct capture beats sub-agent watcher
For one-shot "what does this look like now?" checks, use cb capture and view the PNG yourself with multimodal vision. Round-trip is ~3-5 seconds — faster than spawning a sub-agent.
For multi-event autonomous monitoring (consequential editor events, iterative dialogue across many edits), the sub-agent watcher is right — it idles cheaply and reports curated observations without you having to ask.
| Scenario | Path |
|---|---|
| "I just made a change, did it work?" | cb capture + view PNG yourself |
| "I'll be doing 30 minutes of UMG work, narrate the consequential changes" | Sub-agent watcher with the canonical prompt |
| "Test parity across both browser extensions" | Dual sub-agent watchers (Claude in Chrome + Codex bridge) |
| "Verify a high-stakes lighting bake actually applied" | Sub-agent watcher + verification.needed with framing |
Cadence anti-patterns
Avoid these:
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| 20 tool calls then 1 verification | All errors compound; visual diff is unreadable | One verification per meaningful change |
| Capture only at the end | Silent failures invisible until too late | Capture between every change |
Trust API success without visual confirm | Tools can no-op silently | Visual verification is the only ground truth |
| Capture every micro-edit | Wastes tokens and time | Skip captures for edits where API result IS the visual reality (string variable defaults, function renames) |
Next steps
- EYES MANDATORY — the foundational rule this pattern enforces
- The cb Helper CLI — the fastest path to capture and verify in single commands
- Memory System — record every visual finding so the next agent walks in better-equipped
- Multi-Agent Coordination — the agent bus this pattern uses