Skip to main content
Version: 0.5.0

The cb Helper CLI

ClaudusBridge auto-generates a Python helper script at Saved/ClaudusBridge/cb.py on every MCP initialize. It is the preferred interface for AI agents (and humans) — collapsing the JSON-RPC envelope + python -c '...' unwrap pattern into single-line subcommands with sane defaults.

If you find yourself writing this:

curl -sS -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":\
{"name":"spawn_basic_shape","arguments":{"shape":"Cube",\
"label":"Foo","location":[0,0,200]}}}' \
| python -c "import sys,json; r=json.loads(sys.stdin.read())\
['result']['content'][0]['text']; print(json.loads(r)['data'])"

…stop and use cb instead:

cb spawn Cube label=Foo location=[0,0,200]

Setup

The script is auto-generated and overwritten on every initialize. Don't edit it directly — extend the generator in Source/ClaudusBridge/Private/CBFileGenerators.cpp if you need a new subcommand.

# Convenience alias (Bash / Zsh)
CB='python "C:/Users/Diux/Documents/Unreal Projects/<YOUR_PROJECT>/Saved/ClaudusBridge/cb.py"'
eval "$CB topics"
# PowerShell
function cb { python "C:\Users\Diux\Documents\Unreal Projects\<YOUR_PROJECT>\Saved\ClaudusBridge\cb.py" @args }
cb topics

The script is pure stdlib (urllib.request + argparse + json); no pip install required. It works with any Python 3.8+.


Subcommand reference

cb call <tool> [json_args]

Generic MCP tool dispatch. Args is a JSON object string. Output is the unwrapped data section as JSON.

cb call get_current_map
cb call list_actors '{"class_filter":"StaticMeshActor"}'
cb call set_view_mode '{"mode":"wireframe"}'

The envelope ({result:{content:[{text:"<status/data JSON>"}]}}) is unwrapped automatically. You get the data block directly. On status:"error" from the tool, cb exits non-zero with the error message on stderr.

cb spawn <shape> [k=v ...]

Shorthand for spawn_basic_shape with smart value parsing.

cb spawn Cube label=MyCube location=[0,0,200] color=red
cb spawn Sphere x=420 y=69 z=180 scale=3 color=blue

Three layers of value parsing per k=v token: JSON first (so location=[0,0,200] is a real array, not a string), then float/int, then bare string fallback. Color names auto-expand to UE rgba strings:

NameExpanded value
red(R=1.0,G=0.1,B=0.1,A=1)
green(R=0.1,G=1.0,B=0.1,A=1)
blue(R=0.1,G=0.4,B=1.0,A=1)
yellow(R=1.0,G=0.9,B=0.1,A=1)
orange(R=1.0,G=0.5,B=0.1,A=1)
purple(R=0.6,G=0.2,B=0.8,A=1)
white / black / grayas expected

Pass any other rgba string verbatim if you need a custom color.

cb tx <label>

get_actor_transform <label> — just the transform dict.

cb tx MyCube

Returns location, rotation, scale, bounds, and label.

cb capture [savepath] [--frame ACTOR] [--view MODE]

One-shot screenshot via the Codex in Chrome local bridge. Optional pre-framing:

cb capture
cb capture C:/tmp/shot.png
cb capture --frame MyCube --view lit /tmp/closeup.png

--frame ACTOR calls focus_viewport_on_actor first. --view MODE calls set_view_mode. Both apply BEFORE the capture so the PNG is on-target.

Returns {screenshotPath, bytes, existingTab}. If existingTab: true the user's already-open /preview tab was reused (zero UI activity for the user — preferred). Otherwise a fresh background tab was opened.

Codex bridge required

cb capture requires the Codex in Chrome local bridge running on 127.0.0.1:8791. If it isn't, fall back to your MCP client's browser automation (e.g. Claude in Chrome MCP computer screenshot tool).

cb verify <tool_call> <expected> [--frame ACTOR] [--view MODE]

The iterative verification round-trip in one command:

cb verify "spawn_basic_shape Sphere at [420,69,180]" \
"blue sphere visible at world (420,69,180)" \
--frame Parity_AB_Sphere --view lit

Internally:

  1. Drains primary's queue
  2. Publishes verification.needed { tool_call, expected, framing }
  3. Block-polls primary's queue for verification.confirmed / verification.rejected
  4. Prints [CONFIRMED] or [REJECTED] followed by the watcher's plain-text observation

Exit code 0 on confirmed, 2 on rejected, 1 on timeout. Requires a watcher subscribed on session visual-watcher.

cb pub <channel> <json_payload>

publish_agent_event with sane defaults (from = primary).

cb pub screenshot.request '{"reason":"see what is selected in the outliner"}'
cb pub delegate.material '{"action":"recompile"}' --target visual-watcher

--target SESSION for targeted delivery; omit for broadcast (excludes the sender).

cb poll <session> [channel] [--timeout 60] [--clear|--no-clear]

Block until a matching event lands in <session>'s queue. Replaces the bash until grep ...; do sleep N; done regex loop pattern.

cb poll primary verification.confirmed --timeout 90
cb poll visual-watcher agent_message

Default --clear=true (drains the queue on poll, like the bridge's default).

cb stream

pixel_streaming_status — readiness check before any capture. Always run this if the editor was just relaunched.

cb stream

Returns {ready, signalling_running, streaming_started, viewer_url, preview_bare_url, hint}. Use ready=true as the gate before cb capture.

cb watcher-prompt

Print the canonical SYSTEM PROMPT block from Saved/ClaudusBridge/watcher_subagent.prompt.md (the inner ``` block), ready to pipe into your Agent-spawn primitive.

cb watcher-prompt > /tmp/wp.md
# Then pass /tmp/wp.md to Claude Code's Agent tool, Codex CLI's
# sub-agent spawn primitive, or any other equivalent.

cb sessions

Approximate active session count (via a no-op subscribe).

cb sessions

Memory subcommands

cb also exposes the persistent shared knowledge base. See Memory System for the full pattern.

cb remember <topic> "<summary>" [--body "..."] [--kind tip|gotcha|...] [--tags a,b]
cb recall [topic] # markdown content to stdout
cb topics # tabular listing
cb search <query> # full-text snippets
cb learn # alias for cb recall

Global options

All subcommands accept these:

FlagDefaultEffect
--bridge URLhttp://localhost:3000/mcpMCP HTTP endpoint
--codex URLhttp://127.0.0.1:8791Codex local bridge
--from SESSIONprimary (or subcommand-specific)from_session for pub / remember
--target SESSIONunsettarget_session for pub
--frame ACTORunsetpre-framing actor for capture / verify
--view MODEunsetpre-framing view mode for capture / verify
--timeout SEC60HTTP / poll timeout
--rawoffprint full JSON-RPC response (debugging)

Why use cb instead of raw curl?

Pain point with raw curlHow cb fixes it
~250 chars per call (envelope + escape + unwrap)~50 chars per call
JSON-shell-escape footguns (' inside ', etc.)k=v parsing avoids most quoting
Two-level JSON parsing (outer envelope + inner text)Auto-unwrapped to data
Easy to silently swallow events (grep regex bugs)cb poll is timeout-aware and explicit
Color names need manual rgba expansion every timeBuilt-in name → rgba
Verification round-trip needs 5 calls + parsercb verify collapses to 1

In a typical iterative session of 30 tool calls, cb saves several thousand characters of boilerplate and removes the most common parsing footguns. That's the difference between programming smoothly and fighting JSON-RPC escaping.


Extending cb

The script is generated by FCBToolMetadataRegistry::GenerateCBHelperScript() in Source/ClaudusBridge/Private/CBFileGenerators.cpp. The script body is split across multiple TEXT(R"PY(...)PY") raw-string chunks (each ≲ 8 KB) to stay under MSVC's 16 380-byte per-string-literal limit (C2026 error). FString += concatenates them at runtime; the on-disk cb.py is byte-identical to the source.

To add a new subcommand:

  1. Edit your local Saved/ClaudusBridge/cb.py and add the function.
  2. Re-inject into the generator (the canonical pattern is a small Python script that reads cb.py, splits into chunks ≲ 8 KB, and rewrites the generator function body in CBFileGenerators.cpp).
  3. Rebuild the plugin (Build.bat OCPROEditor Win64 Development …).
  4. Relaunch the editor; the next initialize regenerates cb.py byte-identically to the source.

Next steps